bzoj 1072 狀壓DP

  咱們用w[i][j]來表示,i是一個二進制表示咱們選取了s中的某些位,j表示這些位%d爲j,w[i][j]則表示這樣狀況下的方案數,那麼咱們能夠獲得轉移.w[i|(1<<k)][(j*10+s[k]-'0')%d]+=w[i][j]。spa

  假設s中有x個3,那麼咱們算出的狀態中一樣的數咱們算了x!次,最後除掉就行了。code

/**************************************************************
    Problem: 1072
    User: BLADEVIL
    Language: C++
    Result: Accepted
    Time:476 ms
    Memory:12680 kb
****************************************************************/
 
//By BLADEVIL
#include <cstdio>
#include <cstring>
 
using namespace std;
 
int d,cnt[11],w[3010][1010];
char s[11];
 
int main() {
    int task; scanf("%d",&task);
    while (task--) {
        scanf("%s%d",s,&d); int len=strlen(s);
        memset(cnt,0,sizeof cnt);
        for (int i=0;i<len;i++) cnt[s[i]-'0']++;
        for (int i=0;i<(1<<len);i++) 
            for (int j=0;j<d;j++) w[i][j]=0;
        w[0][0]=1;
        for (int i=0;i<(1<<len);i++)
            for (int j=0;j<d;j++) if (w[i][j])
                for (int k=0;k<len;k++) if (!(i&(1<<k)))
                    w[i|(1<<k)][(j*10+s[k]-'0')%d]+=w[i][j];
        int ans=w[(1<<len)-1][0];
        //printf("%d\n",ans);
        for (int i=0;i<10;i++)
            for (int j=1;j<=cnt[i];j++) {
                ans/=j ;
            }
        printf("%d\n",ans);
    }
    return 0;
}
相關文章
相關標籤/搜索