zoukankan      html  css  js  c++  java
  • [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
  • 相关阅读:
    Android APN开关原理
    HTC Wildfire 闪光灯手电筒的实现方式
    Android Stagefright MPEG4Extractor分析
    Ubuntu 10.10 64bit下使用Android NDK r6编译FFmpeg 0.8.1
    开始IMS学习相关名词和术语(持续更新)
    Ubuntu 下安装代码格式化程序 astyle
    Ubuntu 10.10 x64 安装 ffmpeg tutorial 相关支持库
    关于GradientDrawable的angle属性
    判断SIM卡所属的运营商
    最小生成树算法
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/15623513.html
Copyright © 2011-2022 走看看