hdu4876 暴搜剪枝

来源:互联网 发布:分光计实验的数据记录 编辑:程序博客网 时间:2024/05/17 01:25

hdu4876链接

题意:
n个数中选k个数排成一圈,给一个L,圈中的连续的数的所有异或值中要组成的连续的[L,R]区间,求最大的R(1<=k<=n<=20,k<=6,1<=L<=100)

思路:
一看就是只能暴搜了啊,当时算了下时间复杂度感觉姿势不优美不可搜,现在写完发现确实需要比较优美的姿势才能搜过去。。。
一些剪枝和优化:

  • 选k个数的时候2^n枚举,不要递归搜索
  • 选了k个数之后先2^k枚举所有可能的异或值,判断一下能否组成比[L,ans]大的区间,不能的话不需要做下一步
  • 由于选取k个数排成一圈能产生的连续异或值只有k*(k-1)+1种,所以每次判断就拿这么个范围的桶来做就可以了

代码:

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<algorithm>#include<string>#include<iomanip>#include<vector>#include<set>#include<map>#include<queue>using namespace std;typedef long long LL;typedef unsigned long long ULL;#define rep(i,k,n) for(int i=(k);i<=(n);i++)#define rep0(i,n) for(int i=0;i<(n);i++)#define red(i,k,n) for(int i=(k);i>=(n);i--)#define sqr(x) ((x)*(x))#define clr(x,y) memset((x),(y),sizeof(x))#define max(x,y) (x>y?x:y)#define swap(x,y) {int t=x;x=y;y=t;}#define pb push_back#define mod 1000000007int n,k,L,ans;int a[100],d[100];bool xx[200];void dfs2(int cnt){    if(cnt==k)    {        memset(xx+L,0,sizeof(xx[0])*(k*(k-1)+5));        int tt=0;        for(int len=1;len<k;len++)        {            tt^=d[0];xx[tt]=1;            for(int i=1;i<k;i++)            {                tt^=d[i]^d[(i-len+k)%k];                xx[tt]=1;            }        }        tt^=d[0];        xx[tt]=1;        int t=L;tt=0;        while(xx[t])tt=t,t++;        ans=max(ans,tt);        return;    }    for(int i=cnt;i<k;i++)    {        swap(d[cnt],d[i]);        dfs2(cnt+1);        swap(d[cnt],d[i]);    }}inline void check(){    memset(xx+L,0,sizeof(xx[0])*(k*(k-1)+5));    int tot=1<<k;    for(int i=0;i<tot;i++)    {        int tmp=0;        for(int j=0;j<k;j++)if(i&(1<<j))        {            tmp^=d[j];        }        xx[tmp]=1;    }    int tt=0,t=L;    while(xx[t])tt=t,t++;    if(tt<=ans)return;    if(k==1)    {        ans=max(ans,d[0]);        return;    }    for(int i=1;i<k;i++)    {        swap(d[i],d[1]);        dfs2(2);        swap(d[i],d[1]);    }}int main(){    while(~scanf("%d%d%d",&n,&k,&L))    {        rep0(i,n)scanf("%d",&a[i]);        ans=0;        int tot=1<<n;        for(int i=1;i<tot;i++)if(__builtin_popcount(i)==k)        {            int t=0;            for(int j=0;j<n;j++)if(i&(1<<j))            {                d[t++]=a[j];            }            check();        }        printf("%d\n",ans);    }    return 0;}
0 0