1 条题解

  • 0
    @ 2025-8-24 22:43:13

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar dAniel_lele
    当你在幻想上天会给你开一扇窗的时候,你已经输一半了。

    搬运于2025-08-24 22:43:13,当前版本为作者最后更新于2022-11-03 12:30:25,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    测试点 1~3

    输出不可以,总司令 00 即可。

    测试点 4~5

    输出 [b1=b2][b_1=b_2]。其实输出 11 即可,我没给 00 的点。

    测试点 6~8

    暴力,咋暴力都行,数据太小了。

    测试点 9~11

    这个可以用状压 dpdp,毕竟 bi=1b_i=1

    测试点 12~14

    稍微转化一下,转化为:

    nn 个人要完成 n2\frac{n}{2} 份大作业,两个人一组完成大作业,需要按顺序提交作业,求方案数。

    考虑对于每个人选搭档,第 11 个人有 n1n-1 种选择,第 22 个人 n3n-3 种,以此类推,最后乘 n2!\frac{n}{2}! 即可。

    测试点 15~18

    状压 dp,考虑每次操作已经选个 0/1/20/1/2 个数组中的位置的方案数,可以压位存下来,转移只需要枚举数组这个位置要在哪些操作中被操作即可。复杂度还是要看实现,最快可以达到 O(3bi2×n)O(3^{\frac{\sum b_i}{2}}\times n),慢一点的也能过。

    测试点 19~25

    发现不同操作位置本质相同,首先考虑 dpi,j,kdp_{i,j,k} 表示看到第 ii 个数组位置,有 jj 个操作位置目前为 11kk 个为 22。转移需要枚举往目前 0/10/1 个的位置分别转移多少个,复杂度 O((bi)2(n+bi))O((\sum b_i)^2(n+\sum b_i)),可以通过 192019\sim 20 点。

    容易发现只需要记录 22 操作个数,0/10/1 操作个数都可以通过某些方式计算,时间与空间复杂度变为 O((bi)(n+bi))O((\sum b_i)(n+\sum b_i)),可以通过 212221\sim 22 点。

    然后分析一下,实际上操作位置只有 bi2\frac{\sum b_i}{2} 个,同时空间可以滚动数组优化,最终复杂度为 O((bi)2)O((\sum b_i)^2)14\frac{1}{4} 倍常数,实际循环次数约为 2.25×1082.25\times 10^8,可以通过本题。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    const int mod=998244353;
    int qp(int a,int b){
    	int ans=1;
    	while(b){
    		if(b&1) ans=((long long)ans*a)%mod;
    		a=((long long)a*a)%mod;
    		b>>=1;
    	}
    	return ans;
    }
    int fac[100005],inv[100005];
    void init(){
    	fac[0]=1;
    	for(int i=1;i<=100000;i++) fac[i]=(long long)fac[i-1]*i%mod;
    	inv[100000]=qp(fac[100000],mod-2);
    	for(int i=99999;i>=0;i--) inv[i]=(long long)inv[i+1]*(i+1)%mod;
    }
    int C(int i,int j){
    	if(i<0||j<0||i<j) return 0;
    	return (long long)fac[i]*inv[i-j]%mod*inv[j]%mod;
    }
    int b[50005],n,pre[50005],dp[2][50005];
    signed main(){
    	init();
    	cin>>n;
    	for(int i=1;i<=n;i++) cin>>b[i],pre[i]=pre[i-1]+b[i];
    	if(pre[n]%2==1) return cout<<0,0;
    	int sum=pre[n]/2;
    	dp[0][0]=1;
    	for(int i=1;i<=n;i++){
    	    for(int j=0;j<=sum;j++){
    			int tp2=j,tp1=pre[i-2]-j*2,tp0=sum-tp2-tp1;
    			if(tp0<0) continue;
    			dp[i&1][j]=0;
    	    }
    		for(int j=0;j<=sum;j++){
    			int tp2=j,tp1=pre[i-1]-j*2,tp0=sum-tp2-tp1;
    			if(tp0<0) continue;
    			for(int k=0;k<=b[i];k++){
    				if(tp1<k||tp0<b[i]-k) continue;
    				if(dp[(i&1)^1][tp2]) (dp[i&1][tp2+k]+=(long long)dp[(i&1)^1][tp2]*C(tp1,k)%mod*C(tp0,b[i]-k)%mod)%=mod;
    			}
    		}
    	}
    	cout<<dp[n&1][sum];
    	return 0;
    }
    
    • 1

    信息

    ID
    7726
    时间
    4000ms
    内存
    512MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者