您的位置:首页 > 其它

【数论】君と彼女の恋

2015-08-27 14:15 176 查看
神 「肯定 。美雪 准备了两个 变数 ,记它们为 n和m」

神 「找到一个非 空的非负整数序列 S,满足 S的所有元素之和为 n,而且每个元素对 m取模得到的结果都不相同 」

神 「这种 序列的个数 ,对神的电话号码取模, 就是 命运的数字 」

更加 听不明白 了…… 但是 你能懂的吧。

【嗯…… 怎样 的两个序列算是不同的?】

神 「只要长度不相同,或者 存在 一位 不同 的元素,即为不同序列 」

对于
100% 的数据, n≤10^18,m≤100。

鸽笼原理,数列长度最多为100,考虑状压DP,用fij表示余数选出i个时和为j的方案数,我们可以枚举每个余数,假如选出了cnt个余数,如果n-所有余数之和tot能被m整除,那么这个余数集合合法,接下来给每个数加上m的非负整数倍,并求这样的集合的方案数,等于把(n-tot)/m个无标记小球放入cnt个箱子中,用隔板法求方案数为C(n-tot+cnt-1)(cnt-1),所以这个合法的余数集合的方案数为cnt的阶乘乘上前面那个方案数,然而这还是会T,所以我们不考虑选出哪一个余数,因为只有序列长度和对应的余数和才会影响答案,所以我们用fij来表示集合长度为i,余数和为j的方案数,用类似背包的转移就可以A了,总复杂度O(m^4)

#include<cctype>
#include<cstdio>
#include<map>
#include<cmath>
#include<queue>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<iomanip>
#include<algorithm>
#define mod 905229641
#define LL long long
using namespace std;
LL read()
{
LL x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
LL f[100][5100],n,m;
LL q,an;

void bei()
{
memset(f,0,sizeof(f));
f[0][0]=1;
for (int k=0;k<m;k++)
for (int i=k;i>=0;i--)
for (int j=k*(k-1)/2;j>=0;j--)
{
f[i+1][j+k]=(f[i+1][j+k]+f[i][j])%mod;
}
}
/*
void gcd(LL a,LL b)
{
if (b==0)
{
x=1;
y=0;
return;
}
gcd(b,a%b);
LL t=x;
x=y%mod;
y=(t-a/b*y%mod)%mod;
}

LL multi(LL a,LL b,LL c)
{
int ans=1;
a=a%c;
while(b>0)
{
if(b%2==1)
ans=(ans*a)%c;
b=b/2;
a=(a*a)%c;
}
return ans;
}
*/

int main()
{
n=read();m=read();
int sum=m*(m-1)/2;
bei();
LL ans=0;
for (int i=0;i<=sum;i++)
if ((n-i)%m==0)
{
for (int j=1;j<=m;j++)
{
LL xx=(n-i)/m;
an=(xx+j-1)%mod;
int sum=1;
for (int k=1;k<j;k++)
{
sum=sum*an % mod;
an--;
}
sum=sum*(j*f[j][i]%mod)%mod;
ans=(ans+sum)%mod;
}
// cout<<an<<' '<<q<<' '<<f[k][i]<<' '<<k<<' '<<i<<endl;
}
cout<<ans<<endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Dp 数论