[cf1566H]Xorquiz

记$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 }
View Code
原文地址:https://www.cnblogs.com/PYWBKTDA/p/15623513.html