整数的排列

C: 整数的排列
时间限制: 3 Sec 内存限制: 128 MB

题目描述
给定n整数和一个整数k,对这n个数进行排列,从左到右依次摆放并组成一个大数。求这n个数的排列中,能被k整除的个数占排列总数的比例,以分数形式给出答案
输入
第一行整数n和k(1<=n<=15,1<=k<=100)
第二行n个整数
每个整数最多包含50位,由(‘0’-‘9’)组成。每个整数均没有前导0。每个整数都互不相同。
文件有多组输入数据
输出
输出能被k整除排列占所有排列的比例
样例输入
3 2
3 2 1
5 10
10 100 1000 10000 100000
5 10
11 101 1001 10001 100001
9 21
13 10129414190271203 102 102666818896 1216 1217 1218 101278001 1000021412678412681
1 1
139012963127893461274126478482
样例输出
1/3
1/1
0/1
5183/36288
1/1
题解:
枚举状态 i ,下一个选的数 j ,余数 k
p [ j ] 表示 j 这个数对 m o d 取模的结果。
状态转移方程: d p [ i | ( 1 << ( j 1 ) ) ] [ k 10 l e n [ j ] + p [ j ] ] + = d p [ i ] [ k ] ;
Code:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
char ch[105];
ll dp[(1<<15)][105],mi[105],p[105],len[105],n,mod;
int main()
{
    while(~scanf("%lld%lld",&n,&mod))
    {
        memset(p,0,sizeof(p));
        for(int i=1;i<=n;i++)
        {
            scanf("%s",ch);
            len[i]=strlen(ch);
            for(int j=0;j<len[i];j++)
                p[i]=(p[i]*10+ch[j]-'0')%mod;
        }
        memset(dp,0,sizeof(dp));
        dp[0][0]=1;
        mi[0]=1;
        for(int i=1;i<=100;i++)
            mi[i]=(mi[i-1]*10)%mod;
        for(int i=0;i<(1<<n);i++)
            for(int j=1;j<=n;j++)
                for(int k=0;k<mod;k++)
                {
                    if((1<<(j-1))&i)continue;
                    dp[i|(1<<(j-1))][((ll)k*mi[len[j]]+p[j])%mod]+=dp[i][k];
                }
        ll y=1;
        for(int i=1;i<=n;i++)y*=i;
        ll x=dp[(1<<n)-1][0];
        ll g=__gcd(x,y);
        printf("%lld/%lld\n",x/g,y/g);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_34531807/article/details/80954988