LightOJ 1021 Painful Bases(状态压缩)

题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1021

题意:给出一个B进制的数字x,将x的各位数字(设x包含数字为t)进行全排列得到t!个数字,在这t!数字中,有多少个数字能整数给定的数字K?

思路:f[st][r]表示使用的数字集合为st,余数为r的个数。首先统计出含有i个1的二进制状态,然后对于含有x个1的状态添加一个1得到含有x+1个1的状态。

#include <iostream>

#include <cstdio>

#include <cstring>

#define int64 long long

using namespace std;



int C,B,K,a[20],n,num=0;

char s[20];

int64 f[(1<<16)+5][25];

int p[(1<<16)+5],q[17][(1<<16)+5],cnt[17];



void init()

{

    int i,j;

    for(i=0;i<(1<<16);i++)

    {

        p[i]=0;

        for(j=0;j<16;j++) if(i&(1<<j)) p[i]++;

    }

}



void DP()

{

    memset(f,0,sizeof(f));

    f[0][0]=1;

    int st,r,i,j,k,st0,r0;

    for(i=0;i<n;i++) for(j=0;j<cnt[i];j++)

    {

        st=q[i][j];

        for(r=0;r<K;r++) if(f[st][r])

        {

            for(k=0;k<n;k++) if((st&(1<<k))==0)

            {

                st0=st|(1<<k);

                r0=(r*B+a[k])%K;

                f[st0][r0]+=f[st][r];

            }

        }

    }

}



int main()

{

    init();

    for(scanf("%d",&C);C--;)

    {

        scanf("%d%d",&B,&K);

        scanf("%s",s);

        int i;

        n=strlen(s);

        for(i=0;i<n;i++)

        {

            if(s[i]>='0'&&s[i]<='9') a[i]=s[i]-'0';

            else a[i]=s[i]-'A'+10;

        }

        memset(cnt,0,sizeof(cnt));

        for(i=0;i<(1<<n);i++)

        {

            q[p[i]][cnt[p[i]]++]=i;

        }

        DP();

        printf("Case %d: %lld\n",++num,f[(1<<n)-1][0]);

    }

    return 0;

}

  

 

你可能感兴趣的:(压缩)