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,jk(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,jk(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题的主要内容,如果未能解决你的问题,请参考以下文章

2021辽宁省赛 E.生活大爆炸(计数dp)

2017年ACM第八届山东省赛J题:company

[Lydsy2017年4月月赛]抵制克苏恩题解

21年icpc上海区域赛B题Strange Permutations (容斥+生成函数)

21年icpc上海区域赛B题Strange Permutations (容斥+生成函数)

NBUT 1224 Happiness Hotel 2010辽宁省赛