1. 程式人生 > >bzoj 1072 排列

bzoj 1072 排列

ive () spa des ++i etc 是個 mes char s

Written with StackEdit.

Description

給一個數字串\(s\)和正整數\(d\), 統計s有多少種不同的排列能被\(d\)整除(可以有前導\(0\))。
例如\(123434\)\(90\)種排列能被\(2\)整除,其中末位為\(2\)的有\(30\)種,末位為\(4\)的有\(60\)種。

Input

輸入第一行是一個整數\(T\),表示測試數據的個數,以下每行一組\(s\)\(d\),中間用空格隔開。\(s\)保證只包含數字\(0, 1 , 2, 3, 4, 5, 6, 7, 8, 9.\)

Output

每個數據僅一行,表示能被\(d\)整除的排列的個數。

Sample Input

7
000 1
001 1
1234567890 1
123434 2
1234 7
12345 17
12345678 29

Sample Output

1
3
3628800
90
3
6
1398

HINT

在前三個例子中,排列分別有\(1, 3, 3628800\)種,它們都是\(1\)的倍數。

\(s\)的長度不超過\(10, 1<=d<=1000, 1<=T<=15.\)

Solution

開始覺得就是個弱智\(dfs\),寫了一發,結果\(T\)了.
嚇得我去寫狀壓\(dp\),然後想的時候發現\(dfs\)是可以做的.只是我第一次的枚舉姿勢不對...

  • \(dfs\)過程中傳遞余數\(r\)
    ,枚舉的時候直接枚舉填入\(0\)~\(9\)的哪一個數字,預處理每種數字的個數即可.
  • 開始的時候我是枚舉的填入串中的第幾個數字,算階乘去重把我卡\(T\)了.
#include<bits/stdc++.h>
using namespace std;
typedef long long LoveLive;
inline int read()
{
    int out=0,fh=1;
    char jp=getchar();
    while ((jp>‘9‘||jp<‘0‘)&&jp!=‘-‘)
        jp=getchar();
    if (jp==‘-‘)
        {
            fh=-1;
            jp=getchar();
        }
    while (jp>=‘0‘&&jp<=‘9‘)
        {
            out=out*10+jp-‘0‘;
            jp=getchar();
        }
    return out*fh;
}
const int MAXN=11;
int vis[MAXN];
int ans=0;
char s[MAXN];
int d,n;
int t[MAXN];
void dfs(int k,int r)
{
    if(k>n)
        {
            ans+=(r==0);
            return;
        }
    for(register int i=0;i<=9;++i)
        {
            if(t[i])
                {
                    --t[i];
                    dfs(k+1,(r*10+i)%d);
                    ++t[i];
                }
        }
}
int main()
{
    int T=read();
    while(T--)
        {
            scanf("%s",s+1);
            n=strlen(s+1);
            d=read();
            memset(t,0,sizeof t);
            for(register int i=1;i<=n;++i)
                ++t[s[i]-‘0‘];
            ans=0;
            dfs(1,0);
            printf("%d\n",ans);             
        }
    return 0;
}

bzoj 1072 排列