QOJ.ac
QOJ
ID | 题目 | 提交者 | 结果 | 用时 | 内存 | 语言 | 文件大小 | 提交时间 | 测评时间 |
---|---|---|---|---|---|---|---|---|---|
#619854 | #9380. Match | Green_White | AC ✓ | 41ms | 4400kb | C++20 | 4.3kb | 2024-10-07 15:39:40 | 2024-10-07 15:39:40 |
Judging History
answer
/*
题目翻译:
有两个序列 a,b,以及一张二分图,二分图中左部节点 i 和右部节点 j 有边的条件是:ai^aj>=k。
对每个 1<=k<=n 求二分图大小为 k 的匹配的数量。
这种异或起来大于或小于某个数的题以前有做过:CF1616H Keep XOR Low。
两个思路:一个在 Trie 上考虑,一个直接在序列上考虑,两者殊途同归,为了方便理解我们在 Trie 上考虑。
因为题目要求的是匹配数量,数据范围又很小,考虑直接 dp。
注意因为有两个序列所以我们维护两棵 Trie。
设 f[u][v][i] 表示在 a 序列的 Trie 的 u 子树和 b 序列的 Trie 的 v 子树内选出 i 个匹配的方案数。
1.如果 k 当前这一位为 1。
那么一对匹配不能同时在 ch1[u][0],ch2[v][0] 或同时在 ch1[u][1],ch2[v][1] 子树内。
f[ ch1[u][0] ][ ch2[v][1] ][x]*f[ ch1[u][1] ][ ch2[v][0] ][y] -> f[u][v][x+y]。
2.如果 k 当前这一位为 0。
首先此时的匹配可以是来自:
1.f[ch1[u][0]][ch2[v][0]][x]
2.f[ch1[u][1]][ch2[v][1]][y]
3.ch1[u][0] 和 ch2[v][1] 随便组合
4.ch1[u][1] 和 ch2[v][0] 随便组合
可先算出后两个组合的方案数,再算出三个合在一起的方案数,具体见代码。
代码实现时注意到你开不下 O(60*60*n^3) 的数组,但是儿子的 dp 数组只在父亲有用到,
所以在 dfs 时直接返回 dp 数组,也不需要真的去把 Trie 树建出来。
复杂度的话,看代码的话是每个点有个四重循环,好像是 O(n^5) 但是因为这个转移本质是树形背包,所以其实是 O(n^4)。
因为直接看题解实在看不懂,所以代码参考了一篇题解的代码。
因为 vector 都是动态开空间,所以一定要注意每个 vector 到底要开多少。
这应该是我写过的最高级的代码(指语法)。
*/
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e2+5,mod=998244353;
inline int read(){
int w = 1, s = 0;
char c = getchar();
for (; c < '0' || c > '9'; w *= (c == '-') ? -1 : 1, c = getchar());
for (; c >= '0' && c <= '9'; s = 10 * s + (c - '0'), c = getchar());
return s * w;
}
int n,k,inv[N],fact[N],q[N];
int C(int n,int m){
if(n<m) return 0;
return fact[n]*q[m]%mod*q[n-m]%mod;
}
void Init(){
fact[0]=1;
for(int i=1;i<N;i++) fact[i]=fact[i-1]*i%mod;
inv[1]=1;
for(int i=2;i<N;i++) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
q[0]=1;
for(int i=1;i<N;i++) q[i]=q[i-1]*inv[i]%mod;
}
vector<int> merge1(vector<int> f1,vector<int> f2){ //合并两个 dp 数组
vector<int> dp(f1.size()+f2.size()-1,0);
for(int i=0;i<f1.size();i++)
for(int j=0;j<f2.size();j++)
(dp[i+j]+=f1[i]*f2[j]%mod)%=mod;
return dp;
}
vector<int> merge2(int n,int m){ //表示 n 个左部节点和 m 个右部节点随意匹配的方案数
vector<int> res(min(n,m)+1);
for(int i=0;i<res.size();i++) res[i]=C(n,i)*C(m,i)%mod*fact[i]%mod;
return res;
}
vector<int> dfs(int pos,vector<int> &a,vector<int> &b){
if(a.empty() || b.empty()) return {1};
if(pos==-1) return merge2(a.size(),b.size());
vector<int> A0,A1,B0,B1;
for(int x:a) if(x>>pos&1) A1.emplace_back(x); else A0.emplace_back(x);
for(int x:b) if(x>>pos&1) B1.emplace_back(x); else B0.emplace_back(x);
if(k>>pos&1) return merge1(dfs(pos-1,A0,B1),dfs(pos-1,A1,B0));
vector<int> f1=dfs(pos-1,A0,B0),f2=dfs(pos-1,A1,B1);
vector<int> dp(min(a.size(),b.size())+1,0);
for(int i=0;i<f1.size();i++){
for(int j=0;j<f2.size();j++){
int lstA0=A0.size()-i,lstA1=A1.size()-j; //计算剩余可供合并的点
int lstB0=B0.size()-i,lstB1=B1.size()-j;
vector<int> f3=merge1(merge2(lstA0,lstB1) , merge2(lstA1,lstB0)); //先计算随便匹配的方案数。
for(int k=0;k<f3.size();k++) (dp[i+j+k]+=f1[i]*f2[j]%mod*f3[k]%mod)%=mod;
f3.clear(); f3.shrink_to_fit(); //释放空间
}
}
f1.clear(); f1.shrink_to_fit(); //释放空间
f2.clear(); f2.shrink_to_fit(); //释放空间
return dp;
}
signed main(){
n=read(),k=read();
vector<int> a(n),b(n);
for(int i=0;i<n;i++) a[i]=read();
for(int i=0;i<n;i++) b[i]=read();
Init();
vector<int> ans=dfs(60,a,b);
while(ans.size()<n+1) ans.emplace_back(0);
for(int i=1;i<=n;i++) printf("%lld\n",ans[i]);
return 0;
}
这程序好像有点Bug,我给组数据试试?
详细
Test #1:
score: 100
Accepted
time: 1ms
memory: 3792kb
input:
9 5 1 7 2 8 4 9 2 5 10 1 3 2 4 5 8 8 8 9
output:
51 1034 10768 62195 200965 348924 294444 97344 7200
result:
ok 9 lines
Test #2:
score: 0
Accepted
time: 41ms
memory: 4120kb
input:
200 569102225177443347 1103663383682482176 1103381908705771520 1099441259031822336 1098878309078401024 1089871109823660032 1080863910568919040 1074108511127863296 1071856711314178048 1069041961547071488 1068479011593650176 1067353111686807552 1062849512059437056 1049338713177325568 10448351135499550...
output:
20506 208107723 47878304 53020813 972282728 933586852 658157196 670189811 957980024 366179738 217980591 967482558 833450149 987731802 260904367 5263881 600332344 906061351 658256294 93700706 421323952 178075016 219871690 986880524 848776106 191185484 641917326 576497440 908609746 349728876 606714342...
result:
ok 200 lines
Test #3:
score: 0
Accepted
time: 5ms
memory: 3936kb
input:
200 1098723432450995412 972777519512027136 936748722493063168 864691128455135232 860187528827764736 857935729014079488 856246879153815552 855683929200394240 851180329573023744 848928529759338496 847802629852495872 847310048643252224 847239679899074560 846676729945653248 828662331436171264 8280993814...
output:
8320 34035512 428014253 916072411 696504298 748377440 32424677 188402417 233587075 130639672 759476380 546285625 187068736 159002787 131866334 381530906 133126344 373727612 923311054 725293681 718162548 39511135 322320638 44709653 156884882 285926751 787179409 282967016 153092344 615721347 950855850...
result:
ok 200 lines
Test #4:
score: 0
Accepted
time: 1ms
memory: 4400kb
input:
200 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ...
output:
3072 4412928 940025853 665370743 752672705 581549490 41990996 541401698 170451802 26584141 220983766 844620126 64506869 137621326 418866920 351049174 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ...
result:
ok 200 lines
Test #5:
score: 0
Accepted
time: 2ms
memory: 4104kb
input:
200 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ...
output:
40000 792020000 319908096 286630939 515085548 95626140 472749362 800008042 594973486 139901984 847967250 125664877 254232250 419486325 204481923 979660340 41873095 540955890 585129047 205968776 196086667 674391130 737319172 669580034 973843015 207125612 331414909 119844754 24879477 990932807 8476927...
result:
ok 200 lines
Extra Test:
score: 0
Extra Test Passed