21年辽宁省赛j题
Posted 吃花椒的妙酱
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了21年辽宁省赛j题相关的知识,希望对你有一定的参考价值。
题目大意:nm的棋盘,要求所有nn的地方都有k个棋子,求方案数,n<=100,m<=1e18
思路:dp
首先m的范围是1e18,n的范围100,提示我们有循环节
假如已经确定了第i列放k个棋子,那i+n也只能放k个棋子,显然放k个的方法为
C
n
k
,
k
<
=
n
C_n^k ,k<=n
Cnk,k<=n
预处理出一行放0~n个棋子的方案数
对于第i列,如果它已经确定放k个棋子,那么每个循环节中的第i列都只能放k个,设最后一个循环节到第pos列停止,循环节数量为T,如果i<=pos,则它的方案数贡献数
(
C
n
k
)
T
+
1
(C_n^k)^{T+1}
(Cnk)T+1,否则为
(
C
n
k
)
T
(C_n^k)^{T}
(Cnk)T
Dp[i][j]枚举第i列放k个棋子,则它可从dp[i][j-k]转移来
若i<=pos
d
p
i
,
j
+
=
d
p
i
,
j
−
k
∗
(
C
n
k
)
T
+
1
dp_{i,j} += dp_{i,j-k}*(C_n^k)^{T+1}
dpi,j+=dpi,j−k∗(Cnk)T+1
否则
d
p
i
,
j
+
=
d
p
i
,
j
−
k
∗
(
C
n
k
)
T
dp_{i,j} += dp_{i,j-k}*(C_n^k)^{T}
dpi,j+=dpi,j−k∗(Cnk)T
Dpij表示前I列放了j个棋子的方案数
#include <cmath>
#include <cstring>
#include <algorithm>
#include <map>
#include <list>
#include <queue>
#include <vector>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <deque>
using namespace std;
typedef long long ll;
#define _for(i,a,b) for(int i=(a) ;i<=(b) ;i++)
#define _rep(i,a,b) for(int i=(a) ;i>=(b) ;i--)
#define scd(v) scanf("%d",&v)
#define scdd(a,b) scanf("%d %d",&a,&b)
#define endl "\\n"
#define IOS ios::sync_with_stdio(false),cin.tie(0)
#define pb push_back
#define all(v) v.begin(),v.end()
#define mst(v,a) memset(v,a,sizeof(v))
#define ls p<<1
#define rs p<<1|1a
#define pii pair<int ,int >
#define fi first
#define se second
#define inf 0x3f3f3f3f
#define int long long
const int N = 2e5 + 10;
const int mod = 1e9+7;
int n,m,k;
int c[110][110];
int dp[110][10100];
int C[110],num[110][2];
ll qsm(int a ,int b)
{
int ans=1,temp=a;
while( b )
{
if( b&1 ) ans = (ans * temp)%mod;
temp = ( temp * temp)%mod;
b>>=1;
}
return ans;
}
void de()
{
_for(i,1,n)
{
_for(j,1,i)
{
cout<<c[i][j]<<" ";
}
cout<<endl;
}
cout<<" num "<<endl;
_for(i,1,n) cout<<num[i][0]<<" "<<num[i][1]<<endl;
}
signed main()
{
//freopen("data.txt","r",stdin);
IOS;
cin>>n>>m>>k;
_for(i,0,n) c[i][0]=1;
_for(i,1,n)
{
_for(j,1,i)
{
c[i][j] = (c[i-1][j] + c[i-1][j-1])%mod;
}
}
_for(i,0,n) C[i] = c[n][i];
int T = m/n;
int pos = m - n*T;
_for(i,0,n)
{
num[i][0] = qsm(C[i],T);
num[i][1] = qsm(C[i],T+1);
}
dp[0][0]=1;
_for(i,1,n)
{
_for(j,0,k)
{
_for(t,0,min(j,n))
{
if( i<=pos)
dp[i][j] = (dp[i][j] + dp[i-1][j-t] * num[t][1]%mod)%mod;
else
dp[i][j] = (dp[i][j] + dp[i-1][j-t]*num[t][0]%mod)%mod;
}
}
}
cout<<dp[n][k]<<endl;
}
以上是关于21年辽宁省赛j题的主要内容,如果未能解决你的问题,请参考以下文章
21年icpc上海区域赛B题Strange Permutations (容斥+生成函数)