題目大意: 求n個20位0、1二進制串中,兩兩抑或最少的1的個數。 解題思路: 兩種解法: 1、20位 一共有1<<20個狀態,先預處理1的個數,並把相同的1的個數的狀態放到一個集合裡。根據0和其它數抑或得相同,1和其它數抑或得反,從小到大枚舉1的個數的狀態P,用其中一個串A來和P相抑或,得到B ,如果B在給定的串中,說明A^B中1的個數為P中1的個數。 這種解法的最壞時間復雜度為C(20,10)*n*20 很暴力,數據很弱。 代碼:
#include<iostream> #include<cmath> #include<cstdio> #include<cstdlib> #include<string> #include<cstring> #include<algorithm> #include<vector> #include<map> #include<set> #include<stack> #include<list> #include<queue> #define eps 1e-6 #define INF 0x3fffffff #define PI acos(-1.0) #define ll __int64 #define lson l,m,(rt<<1) #define rson m+1,r,(rt<<1)|1 #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; #define Maxn 110000 //0和a抑或得相同 //1和a抑或得相反 bool hav[1<<20]; vector<int>myv[25]; //myv[i]表示含有i個1的狀態 int sa[Maxn]; int main() { int t,n; for(int i=0;i<(1<<20);i++) { int num=0; for(int j=0;j<20;j++) if(i&(1<<j)) num++; myv[num].push_back(i); //含1的個數相同的狀態放到一個集合裡 } scanf("%d",&t); while(t--) { scanf("%d",&n); memset(hav,false,sizeof(hav)); bool flag=false; for(int i=1;i<=n;i++) { scanf("%X",&sa[i]); if(hav[sa[i]]) flag=true; else hav[sa[i]]=true; } if(flag) { puts("0"); continue; } for(int i=1;i<=20&&!flag;i++) for(int j=1;j<=n&&!flag;j++) { for(int k=0;k<myv[i].size()&&!flag;k++) { if(hav[sa[j]^myv[i][k]]) { printf("%d\n",i); flag=true; } } } } return 0; }
2、因為最終結果肯定在1~20之間,結果域較小。得到結果的概率較大,所以隨機兩個串的標號,直接計算就可以,隨機1000000次。預處理會減少枚舉次數。 代碼:
#include<iostream> #include<cmath> #include<cstdio> #include<cstdlib> #include<string> #include<cstring> #include<algorithm> #include<vector> #include<map> #include<set> #include<stack> #include<list> #include<queue> #define eps 1e-6 #define INF 0x3fffffff #define PI acos(-1.0) #define ll __int64 #define lson l,m,(rt<<1) #define rson m+1,r,(rt<<1)|1 #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; #define Maxn 110000 int sa[Maxn]; bool hav[1<<20]; int Cal(int a) { int res=0; while(a) { if(a&1) res++; a>>=1; } return res; } int main() { int t,n; scanf("%d",&t); while(t--) { scanf("%d",&n); memset(hav,false,sizeof(hav)); bool flag=false; for(int i=1;i<=n;i++) { scanf("%X",&sa[i]); if(hav[sa[i]]) flag=true; else hav[sa[i]]=true; } if(flag) { printf("0\n"); continue; } int ans=20; // srand((unsigned)time(NULL)); for(int i=1;i<=1000000;i++) { int j=rand()%n+1; int k=rand()%n+1; if(j==k) continue; ans=min(ans,Cal(sa[j]^sa[k])); } printf("%d\n",ans); } return 0; }