毒瘤大合集。
$T1$基本没有暴力分但是正解是两个暴力的合集。。然后单纯只写其中比较简单的那一个的话一分都没有。。
$T2$写的暴力正解不知道是啥东西。但是我数组开i太大,本机没事但交上去$CE$了。(把我根本没调用过的杜教筛哈希表给删了就不$CE$了)
然而也只有$10$分。常数丑了。把所有数组都缩小到$frac{1}{10}$就有$20$分了。奇奇怪怪。
$T3$是个毒瘤卡常的交互题,复杂度明明是$O(n log n)$但是因为所谓实测非得卡到$O(10n)$.
然而我并没有什么想法,毕竟只会写$O(n^2)$的,正解优化的思路还是不错。但是因为毒瘤卡常所以还是耽误了我一下午的时间。
不知道为什么并没有留更多的改题时间,所以苟过$T3$然后把$T1$的高分暴力写了就结束了。
啊啊啊我的视频课啊。。。
T1:任凭风浪起,稳坐钓鱼台
大意:给$n$个$k$位二进制数,求两两异或的立方和。$nk le 2 imes 10^6$
对于$k geq 128$直接暴力,手写$bitset$压位,$2^{64}$进制效果不错。
对于$k<128$,逐位考虑贡献。发现立方就是可重复的选择三位,如果这三位在两个数中异或值都为$1$那么就产生这三位的乘积的贡献。
于是用$bitset$压一压有哪些数这一位上是1哪些数是0,然后与一与就好了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ull unsigned long long 4 #define mod 998244353 5 unsigned int seed;int n,k,x,ans,bit[1<<16];ull jz=((1ull<<63)%mod<<1)%mod,pw[555]; 6 vector<ull>b[20005],r,c[20005]; 7 ull get01(){ 8 seed^=seed<<13; 9 seed^=seed>>17; 10 seed^=seed<<5; 11 return seed&1; 12 } 13 int cnt(ull s){return bit[s&65535]+bit[s>>16&65535]+bit[s>>32&65535]+bit[s>>48];} 14 int main(){ 15 cin>>n>>k>>x>>seed; 16 if(k>=128){ 17 for(int i=1;i<=n;++i)b[i].resize((k>>6)+1);r.resize((k>>6)+1); 18 for(int i=1;i<=n;++i)for(int j=0;j<k;++j)b[i][j>>6]|=get01()<<(j&63); 19 const int K=k-1>>6; 20 for(int i=1;i<=n;++i)for(int j=i+1;j<=n;++j){ 21 for(int x=0;x<=K;++x)r[x]=(b[i][x]^b[j][x])%mod; 22 ull tot=0,p=1; 23 for(int x=0;x<=K;++x)tot=(tot+p*r[x])%mod,p=p*jz%mod; 24 ans=(ans+tot*tot%mod*tot)%mod; 25 }cout<<ans<<endl;return 0; 26 }const int N=n-1>>6; r.resize(N+1); 27 for(int i=0;i<k;++i)b[i].resize(N+1),c[i].resize(N+1); 28 for(int i=0;i<n;++i)for(int j=0;j<k;++j)b[j][i>>6]|=get01()<<(i&63),c[j][i>>6]|=b[j][i>>6]&(1ull<<(i&63))^(1ull<<(i&63)); 29 pw[0]=1; 30 for(int i=1;i<555;++i)pw[i]=(pw[i-1]+pw[i-1])%mod; 31 for(int i=1;i<1<<16;++i)bit[i]=bit[i>>1]+(i&1); 32 for(int i=0;i<k;++i)for(int j=i;j<k;++j)for(int x=j;x<k;++x){ 33 int _000=0,_001=0,_010=0,_011=0,_100=0,_101=0,_110=0,_111=0; 34 for(int y=0;y<=N;++y) 35 _000+=cnt(c[i][y]&c[j][y]&c[x][y]), 36 _001+=cnt(c[i][y]&c[j][y]&b[x][y]), 37 _010+=cnt(c[i][y]&b[j][y]&c[x][y]), 38 _011+=cnt(c[i][y]&b[j][y]&b[x][y]), 39 _100+=cnt(b[i][y]&c[j][y]&c[x][y]), 40 _101+=cnt(b[i][y]&c[j][y]&b[x][y]), 41 _110+=cnt(b[i][y]&b[j][y]&c[x][y]), 42 _111+=cnt(b[i][y]&b[j][y]&b[x][y]); 43 int r=i==x?1:(i==j||j==x?3:6); 44 ans=(ans+(1ll*_000*_111+1ll*_001*_110+1ll*_010*_101+1ll*_011*_100)%mod*pw[i+j+x]*r)%mod; 45 }cout<<ans<<endl; 46 }
对于异或这种操作,上面我们是枚举了每一位的$01$。然而为什么不能直接去做异或呢?
发现这道题貌似可以直接对若干位异或$fwt$。
我们把二进制位每$a$位分为一组,然后我们要从中选出三个数位的话,那么只需要选出三个数位分别在哪一组里。
T2:任凭风浪起,稳坐钓鱼台(续)
鸽了鸽了等$skyh$大神讲了。
T3:鱼和熊掌不可兼得
大意:交互。实现一个函数猜中一个$n$排列。可以调用一个函数,返回排列中对位正确的有多少个。$n le 5000,limit le 10n$
首先为了方便随机出一个错排。
然后交换关系相当与$frac{n(n-1)}{2}$条边。
因为已经是错排了,所以交换的结果只会使正确数增加,那么这条边就使至少一个数字归位了。
把所有这样有用的边都记下来,那么整个序列就被分成了若干环。
现在问题是如何在合法查询次数内知道哪条边是否有用。
发现只要没有公共点,那么边之间是互不影响的。
那么我们就可以指定一个没有公共点的边集同时交换它们然后进行$count$。如果有数就证明这组边里至少有一条有用的。
然后递归分治下去就能找到哪些边是有用的。
所以现在的问题是如何把$frac{n(n-1)}){2}$条边分成尽量少的组使之没有公共点。
发现边两端点的编号和对$n$取模就是一个合理的组编号。
因为如果有公共点那么相当于一个数就一定锁定了。为了让模后相等在同一个组内,那么另一个数也要相等,那就是重边了。。。
所以如此分组然后分治,最后$dfs$弄环就可以了。
然而有几个小细节用来卡常,毕竟这题应该是$O(nlogn)$的且附带一些不小的常数,然而卡成$10n$也就非常无良了。
首先对于一个点如果它的有用边度数已经达到了2那么以后关于这个点的边就不必加入分治了。
其次分治时传一个参数是这里面所有边对$count$的总贡献。然后查询左儿子时,右儿子的值也就可以直接做差得到了。
再之最后$dfs$的复杂度应该是环数级别的,而不能是点数级别的。
然后就大概在最后一个子任务$49199$过去了。无良出题人。。
1 #include"game.h" 2 using namespace std; 3 #define S 5555 4 int x[5555],y[5555],c,mt[5555],e[5555][3],al[5555],C,top;vector<int>a,r; 5 void cl(int l,int r){for(int i=l;i<=r;++i)swap(a[x[i]],a[y[i]]);} 6 void DaC(int l,int r,int zz){ 7 if(l==r){ 8 e[x[l]][++mt[x[l]]]=y[l];e[y[l]][++mt[y[l]]]=x[l]; 9 if(zz^1)e[x[l]][++mt[x[l]]]=y[l],e[y[l]][++mt[y[l]]]=x[l]; return; 10 } 11 cl(l,l+r>>1);int $=count(a);cl(l,l+r>>1);if($)DaC(l,l+r>>1,$); 12 if($!=zz)DaC((l+r>>1)+1,r,zz-$); 13 } 14 void dfs(int p,int nt=1){ 15 al[p]=nt;top++; 16 for(int i=1;i<3;++i)if(al[e[p][i]]!=nt)swap(a[p],a[e[p][i]]),dfs(e[p][i],nt); 17 } 18 vector<int>guess(int n,int l){ 19 a.resize(n);r.resize(n); 20 for(int i=1;i<=n;++i)a[i-1]=i; 21 srand(time(0)); 22 while(count(a))random_shuffle(a.begin(),a.end()); 23 for(int i=0;c=0,i<n;++i){ 24 for(int j=0;j<n;++j)if(mt[j]!=2&&mt[(i-j+n)%n]!=2&&j<(i-j+n)%n)x[++c]=j,y[c]=(i-j+n)%n; 25 if(c){cl(1,c);int x=count(a);cl(1,c);if(x)DaC(1,c,x);} 26 } 27 for(int i=0,lc=0;i<n;++i)if(!al[i]){ 28 top=1; 29 for(int j=0;j<n;++j)r[j]=a[j]; 30 al[i]=1;swap(a[i],a[e[i][1]]);dfs(e[i][1]); 31 int C=count(a);if(C==lc+top){lc=C;continue;} 32 for(int j=0;j<n;++j)a[j]=r[j];lc+=top; 33 al[i]=2;swap(a[i],a[e[i][2]]);dfs(e[i][2],2); 34 }return a; 35 }