sgu 223 状态压缩+方案数

来源:互联网 发布:程序员转行干什么 编辑:程序博客网 时间:2024/05/18 03:21

由于每颗棋子只影响下一行状态,首先dfs出两行合法转移状态,再枚举状态和个数求解。


ACcode:

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;typedef long long LL;const int LIM=1024;const int NS=1000000;int num[LIM];LL dp[2][LIM][26];int state[NS][2],top;int getone(int x){    int cnt=0;    for (; x; cnt++,x&=(x-1));    return cnt;}void dfs(int x,int y,int pos){    if (pos<0) return ;    if (pos==0)    {        state[top][0]=x;        state[top++][1]=y;        return ;    }    int a=x&1,b=y&1;    dfs(x<<1,y<<1,pos-1);    if (!(a|b))    dfs(x<<1|1,y<<1,pos-1),    dfs(x<<1,y<<1|1,pos-1);}void print(int x,int y){    for (int i=0; i<y; i++,x>>=1)        printf("%d",x&1);    puts("");}int move(int x){    return (x|(x<<1)|(x>>1));}void ttt(int n){    int cnt=0;    printf("top=%d\n",top);    for (int i=0; i<top; i+=100)    {        printf("i=%d\n",i);        print(state[i][0],n);        print(state[i][1],n);    }    printf("cnt=%d\n",cnt);}void init(int x,int y,int z){    for (int i=0;i<LIM;i++)    for (int k=0;k<=z;k++)    dp[x][i][k]=0;}int main(){    int n,k,p,q,r,s,t;    for (int i=0; i<LIM; i++)        num[i]=getone(i);    while (~scanf("%d%d",&n,&k))    {        t=(n+1)>>1;        if (t*t<k)        {            printf("0\n");            continue;        }        s=top=0;        dfs(0,0,n),init(0,n,k);       // ttt(n);        for (int i=0;i<top;i++)        {            p=state[i][0];            dp[0][p][num[p]]=1;        }        for (int i=2;i<=n;i++)        {            s^=1,init(s,n,k);            for (int j=0;j<top;j++)            {                p=state[j][0],q=state[j][1],t=num[q];                for (int c=num[p];c<=(k-t);c++)                dp[s][q][c+t]+=dp[1-s][p][c];            }        }        LL res=0;        for (int i=0;i<LIM;i++)        res+=dp[s][i][k];      //  cout<<res<<endl;        printf("%I64d\n",res);    }    return 0;}


原创粉丝点击