Codeforces 769D
太久没写搜索因为递归边界问题卡了很久。。
题意:定义k-interesting:如果两个数的二进制形式有k位不相同,则称之为k-interesting。给出n和k,输入n个大小在[0,10000]之间的数,问有多少对ai,aj(i<j)是k-interesting数。
解题思路:注意到n个数的大小特地限制在10000以下,考虑暴力搜索,复杂度为10000*(2^14),复杂度太高,需要剪枝:当k小于7,计算k位不相同的数有哪些;k大于等于7,计算14-k位相同的数有哪些。使用vector存储搜索结果,遍历一遍即可(结果需用long long存储,极端情况下答案为n^2级别)
代码如下:(表现十分不佳——1699ms,大概还是姿势太挫了。。??)
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<vector> using namespace std; typedef long long ll; #define sqr(x) ((x)*(x)) const int N=1e4+10; int n,k,a[N*10],tot[N*10]; vector<int>all[N]; void dfs(int x,int num,int pos,int cnt,int rev){ if(cnt<0) return; if(pos==-1){ if(!cnt){ all[x].push_back(num); return; } return; } int tmp=1<<pos; if(num&tmp) tmp*=-1; num+=tmp; dfs(x,num,pos-1,rev?cnt:cnt-1,rev); num-=tmp; dfs(x,num,pos-1,rev?cnt-1:cnt,rev); } void init(){ int rev=k>=7?1:0; if(rev) k=14-k; for(int i=0;i<=10000;i++){ all[i].clear(); dfs(i,i,13,k,rev); } memset(tot,0,sizeof(tot)); } int main(){ //freopen("in.txt","r",stdin); while(~scanf("%d%d",&n,&k)){ init(); for(int i=0;i<n;i++) scanf("%d",a+i); ll res=0; for(int i=n-1;i>=0;i--){ for(int j=0;j<all[a[i]].size();j++) if(tot[all[a[i]][j]]){ res+=tot[all[a[i]][j]]; } tot[a[i]]++; } printf("%I64d\n",res); } return 0; }