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;
}

 

posted @ 2017-03-14 15:48  轶辰  阅读(270)  评论(0编辑  收藏  举报