cf 241D
题目大意:
给你n个数和p,都小于50000要求留下若干个数字,使得剩下的数字异或为0,并且从左到右串联起来可以被p整除,求一种这样的方案。
搜索
奇技淫巧题
我们无视排列中所有>25的元素。因为由1~25组成的异或和为0的方案有1048576个,已经远大于50000。在这么多种方案下,一个序列拼起来模p几乎可以看作是一个随机函数,异或和为0跟拼起来模p等于0之间几乎没有相关性。那也就是说我们在1~25之内找不到合法解的概率是
$\left ( \frac{49999}{50000} \right )^{1048576}\approx 7.8\ast 10^{-10}$
推广一下,假设只考虑所有≤2l2l的数,那么由1∼2l1∼2l组成的异或和为 00 的方案大约会有 22l2l22l2l 个。即总方案数 22l22l,除以总的结果方案数 2l2l(答案为0的只有12l12l 概率)
在如此大概率能找到解的情况下,可以通过本题。
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 #define rep(i,a,b) for(int i=a;i<=b;i++) 6 #define Rep(i,a,b) for(int i=a;i>=b;i--) 7 #define ms(i,a) memset(a,i,sizeof(a)) 8 template<class T>void read(T &x){ 9 x=0; char c=0; 10 while (!isdigit(c)) c=getchar(); 11 while (isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar(); 12 } 13 template<class T>void write(T x){ 14 if(x>9) write(x/10); 15 putchar(48+x%10); 16 } 17 18 int const maxn=26; 19 int n,p,a[maxn],b[maxn],m,check,pos[maxn]; 20 21 int inline pw(int x){ 22 return x<10? 10:100; 23 } 24 25 void dfs(int k,int x,int y,int num){ 26 if(x==0 && y==0 && num){ 27 puts("Yes"); write(num);putchar('\n'); 28 rep(i,1,num) write(b[i]),putchar(' '); exit(0); 29 } 30 if(k>m) return ; 31 dfs(k+1,x,y,num); 32 b[num+1]=pos[a[k]]; 33 dfs(k+1,x^a[k],(y*pw(a[k])+a[k])%p,num+1); 34 } 35 int main(){ 36 read(n);read(p); 37 rep(i,1,n){ 38 int x;read(x); 39 if(x<maxn) a[++m]=x,pos[x]=i; 40 } 41 dfs(1,0,0,0); 42 puts("No"); 43 return 0; 44 }