Codeforces Round 925 (Div. 3) G. One-Dimensional Puzzle【推公式+组合数学+隔板法】

原题链接:https://codeforces.com/problemset/problem/1931/G

题目描述:

有 4 种拼图,其中第 i 种拼图有 ci​ 张。

两张拼图可以连结当且仅当它们相邻的卡槽中一个凹陷一个突出。

我们希望将所有的拼图从左往右拼起来,求总方案数。答案对 998244353 取模。

输入输出描述:

多测。1≤t≤2×10^5,0≤ci​≤10^6,∑(c1​+c2​+c3​+c4​)≤4×10^6。

输入输出样例
输入 
11
1 1 1 1
1 2 5 10
4 6 100 200
900000 900000 900000 900000
0 0 0 0
0 0 566 239
1 0 0 0
100 0 100 0
0 0 0 4
5 5 0 2
5 4 0 5
输出 
4
66
0
794100779
1
0
1
0
1
36
126

解题思路:

四种图形的个数分别是c1,c2,c3,c4,首先只考虑第一种图形和第二种图形,如果abs(c1-c2)>1,那么必然多出一个第一种图形或者第二种图形无法插入链中,这个可以自己画图分析一下,这里不做具体描述,然后就是abs(c1-c2)<=1的情况。

当c1==c2时,如下图所示:

对于图形3会有c1种插入位置,图形4会有c2+1中插入位置,此时这个问题就可以转换为了将b个球放进a个盒子有多少种放法了,允许某些盒子为空,我们不妨设为f(a,b),实际上我们可以把这个过程看为将a+b个球放进a个盒子中有多少种放法,此时不允许出现空盒子,这里就相当于在a+b-1个空选择a-1个板子插入,就是C(a+b-1,a-1),对应到这里就是C(c1+c3-1,c1-1)*C(c2+c4,c2),然后如果按照[2,1,2,1,2,1]的方式排列,那么图形3有c1+1插入位置,图形4有c2种插入位置,那么就是C(c1+c3,c1)*C(c2+c4-1,c2-1),这俩种情况加起来即可。

当abs(c1-c2)==1时,如下图所示:

对于c1==c2-1或者c1==c2+1俩种情况,对于图形3和图形4都有max(c1,c2)种插入位置,同上分析,首先不妨设c=max(c1,c2),那么这里就是C(c+c3-1,c-1)*C(c+c4-1,c-1)。

还要注意特判一些边界情况,当c1==c2时,有可能c1==c2==0,那么如果此时c3!=0 && c4!=0,这种情况无法拼出一条链,输出0,也就是在图形1和图形2的个数都是0时,不允许图形3和图形4同时出现。

到这里就分析的差不多了,由于多测数据,我们需要提前预处理组合数,预处理之后,对于每组测试数据直接根据推导出的公式直接输出答案即可。

时间复杂度:O(T+nlog(n)),T表示测试数据组数,n=2e6。

空间复杂度:O(n),n=2e6。

cpp代码如下:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;
typedef long long LL;

const int N = 2e6 + 10, mod = 998244353;  //注意这里不是模(1e9+7),我开始习惯性写成(1e9+7)导致wa好几发

int T;
int fact[N],infact[N];

int qmi(int x,int k,int p)
{
    int res=1;
    while(k)
    {
        if(k&1)res=1ll*res*x%p;
        x=1ll*x*x%p;
        k>>=1;
    }
    return res;
}
void init()  //预处理组合数
{
    fact[0]=infact[0]=1;
    for(int i=1;i<N;i++)
    {
        fact[i]=1ll*fact[i-1]*i%mod;
        infact[i]=1ll*infact[i-1]*qmi(i,mod-2,mod)%mod;
    }
}

int C(int n,int m)
{
    if(n<0 || m<0)return 0;
    return 1ll*fact[n]*infact[m]%mod*infact[n-m]%mod;
}
void solve()
{
    int c1,c2,c3,c4;
    cin>>c1>>c2>>c3>>c4;
    if(abs(c1-c2)>1){ 
        cout<<0<<'\n';
        return ;
    }
    if(c1==c2){
        if(!c1){  //特判边界情况
            if(c3 && c4)cout<<0<<'\n';
            else cout<<1<<'\n';
        }else {
            cout<<(1ll*C(c1+c3-1,c1-1)*C(c2+c4,c2)%mod+1ll*C(c1+c3,c1)*C(c2+c4-1,c2-1)%mod)%mod<<'\n';
        }
    }else {
        int c=max(c1,c2);
        cout<<1ll*C(c+c3-1,c-1)*C(c+c4-1,c-1)%mod<<'\n';
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    init();
    cin>>T;
    while(T--)
    {
        solve();
    }
    return 0;
}
Codeforces Round 894 (Div. 3) 是一个Codeforces举办的比赛,是第894轮的Div. 3级别比赛。它包含了一系列题目,其中包括题目E. Kolya and Movie Theatre。 根据题目描述,E. Kolya and Movie Theatre问题要求我们给定两个字符串,通过三种操作来让字符串a等于字符串b。这三种操作分别为:交换a中相同位置的字符、交换a中对称位置的字符、交换b中对称位置的字符。我们需要先进行一次预处理,替换a中的字符,然后进行上述三种操作,最终得到a等于b的结果。我们需要计算预处理操作的次数。 根据引用的讨论,当且仅当b[i]==b[n-i-1]时,如果a[i]!=a[n-i-1],需要进行一次操作;否则不需要操作。所以我们可以遍历字符串b的前半部分,判断对应位置的字符是否与后半部分对称,并统计需要进行操作的次数。 以上就是Codeforces Round 894 (Div. 3)的简要说明和题目E. Kolya and Movie Theatre的要求。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Codeforces Round #498 (Div. 3) (A+B+C+D+E+F)](https://blog.csdn.net/qq_46030630/article/details/108804114)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [Codeforces Round 894 (Div. 3)A~E题解](https://blog.csdn.net/gyeolhada/article/details/132491891)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值