记$mn_{x}$为$x$所有素因子乘积(约定$mn_{1}=1$),并构造集合$S=\{x\mid x\in \Z[1,c],x=mn_{x}\}$
显然仅需询问$S$中的数,打表可得$|S|\le \lceil 0.65 c\rceil$,并记询问$x$的结果为$g(x)$
对于$mn_{x}$相同的数,每一次询问其必然同时参与/不参与,因此至多只能得到其异或和
而事实上,这是可以得到的,因此问题即求$\forall x\in S,f(x)=\bigoplus_{i\in A,mn_{i}=x}i$
对$g$和$f$均容斥,不难得到$g(x)=\bigoplus_{d\mid x}\bigoplus_{i\in A,d\mid i}i$和$f(x)=\bigoplus_{d\in S,x\mid d}\bigoplus_{i\in A,d\mid i}i$
记$h(d)=\bigoplus_{i\in A,d\mid i}i$,也即$g(x)=\bigoplus_{d\mid x}h(d)$和$f(x)=\bigoplus_{d\in S,x\mid d}h(d)$
前者由莫比乌斯反演,可得$h(x)=\bigoplus_{d\mid x}g(d)$,进而将两式分别暴力$o(n\log n)$计算即可
求出$f(x)$后,再利用线性基对$mn_{i}=x$的$i$求出若干组异或和为$f(x)$的解(对不在线性基中的变量随机),根据随机性,不妨认为对每一个$x$选一组解,存在一种选法使得$|A|=n$
先选定一组解,以解的大小差为物品背包,并使用bitset优化,由于空间限制在实现时需要滚动,那么问题即如何求出具体的方案
关于这个问题,可以记录每一个"体积"第一次变为1时所选的物品,那么选上该物品并重复此过程即可
一些实现上的细节问题:
1.对于大小为0的物品需要忽略,否则复杂度会过高
2.(可能是我脸太黑了?)对每一组求了9组解,并且线性基外选入概率调成$\frac{4}{9}$才过
时间复杂度为$o(c\log c)$,可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 1000005 4 #define L 20 5 #define T 9 6 #define fi first 7 #define se second 8 bitset<N>bt,bt0,Bt; 9 vector<int>v0,va,vb,v[N],sol[N][T]; 10 int n,m,q,vis[N],p[N],mn[N],h[N],g[N],f[N],a[L],P[L],d[N][T]; 11 pair<int,int>pos[N]; 12 int add(int k){ 13 int s=0; 14 for(int i=0;i<L;i++) 15 if (k&(1<<i)){ 16 if (!a[i]){ 17 a[i]=k,P[i]=s; 18 return i; 19 } 20 k^=a[i],s^=P[i]; 21 } 22 return -1; 23 } 24 int query(int k){ 25 int s=0; 26 for(int i=0;i<L;i++) 27 if (k&(1<<i)){ 28 if (!a[i])return -1; 29 k^=a[i],s^=P[i]; 30 } 31 return s; 32 } 33 int main(){ 34 srand(time(0)); 35 scanf("%d%d",&n,&m); 36 mn[1]=1; 37 for(int i=2;i<=n;i++){ 38 if (!vis[i])p[++p[0]]=i,mn[i]=i; 39 for(int j=1;(j<=p[0])&&(i*p[j]<=n);j++){ 40 vis[i*p[j]]=1; 41 if (i%p[j])mn[i*p[j]]=mn[i]*p[j]; 42 else{ 43 mn[i*p[j]]=mn[i]; 44 break; 45 } 46 } 47 } 48 for(int i=1;i<=n;i++){ 49 v[mn[i]].push_back(i); 50 if (mn[i]==i)v0.push_back(i); 51 } 52 printf("%d",(int)v0.size()); 53 for(int i=0;i<v0.size();i++)printf(" %d",v0[i]); 54 printf("\n"); 55 fflush(stdout); 56 for(int i=0;i<v0.size();i++)scanf("%d",&g[v0[i]]); 57 for(int i=0;i<v0.size();i++) 58 for(int j=v0[i];j<=n;j+=v0[i]) 59 if (mn[j]==j)h[j]^=g[v0[i]]; 60 for(int i=0;i<v0.size();i++) 61 for(int j=v0[i];j<=n;j+=v0[i]) 62 if (mn[j]==j)f[v0[i]]^=h[j]; 63 int nn=m; 64 for(int i=0;i<v0.size();i++){ 65 va.clear(),vb.clear(); 66 for(int j=0;j<L;j++)a[j]=P[j]=0; 67 for(int j=0;j<v[v0[i]].size();j++){ 68 int x=add(v[v0[i]][j]); 69 if (x<0)vb.push_back(v[v0[i]][j]); 70 else{ 71 P[x]|=(1<<va.size()); 72 va.push_back(v[v0[i]][j]); 73 } 74 } 75 for(int t=0;t<T;t++){ 76 int s=f[v0[i]]; 77 for(int j=0;j<vb.size();j++) 78 if (rand()%9<4){ 79 s^=vb[j]; 80 sol[i][t].push_back(vb[j]); 81 } 82 s=query(s); 83 for(int j=0;j<va.size();j++) 84 if (s&(1<<j))sol[i][t].push_back(va[j]); 85 } 86 for(int x=0;x<T;x++) 87 for(int y=x+1;y<T;y++) 88 if (sol[i][x].size()>sol[i][y].size())swap(sol[i][x],sol[i][y]); 89 nn-=sol[i][0].size(); 90 for(int t=1;t<T;t++)d[i][t]=sol[i][t].size()-sol[i][0].size(); 91 } 92 if (nn<0)return 1; 93 bt[0]=1; 94 for(int i=0;i<v0.size();i++){ 95 if (!d[i][T-1])continue; 96 bt0=bt; 97 for(int t=1;t<T;t++){ 98 if (!d[i][t])continue; 99 Bt=((bt0<<d[i][t])&(~bt)); 100 for(int j=Bt._Find_first();j<N;j=Bt._Find_next(j))pos[j]=make_pair(i,t); 101 bt|=Bt; 102 } 103 } 104 if (!bt[nn])return 2; 105 memset(vis,0,sizeof(vis)); 106 for(int i=nn;i;i-=d[pos[i].fi][pos[i].se])vis[pos[i].fi]=pos[i].se; 107 for(int i=0;i<v0.size();i++){ 108 int p=vis[i]; 109 for(int j=0;j<sol[i][p].size();j++)printf("%d ",sol[i][p][j]); 110 } 111 printf("\n"); 112 return 0; 113 }