时间限制: 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
题解:
枚举状态 ,下一个选的数 ,余数 。
表示 这个数对 取模的结果。
状态转移方程:
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);
}
}