1 条题解

  • 0
    @ 2025-8-24 23:15:37

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Purslane
    AFO

    搬运于2025-08-24 23:15:37,当前版本为作者最后更新于2025-05-09 21:38:04,作者可能在搬运后再次修改,您可在原文处查看最新版

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

    以下是正文


    Solution

    我做这个题,花了将近 2 个小时……如此水平,如何 NOI!/ll

    不过克罗地亚国家队在这道题上得分 max\max44


    考虑 k=nk=n 怎么做,也就是所有点都在某一条 1n1 \to n 路径上。

    考虑让 11n1n-1 每个点至少有一条出边,这样可以保证所有点都能到 nn。而只要除了 11 以外所有点入度都不是 00,就能保证 11 能到达所有点。

    那么直接施加容斥。设 dpi,jdp_{i,j} 为,考虑了后 ii 个点,有 jj 个点被钦定了入度为 00(特别的,倒数第 ii 个点此时不能被钦定,只能在转移的时候被钦定。即,j<ij < i)。这个可以 O(n2)O(n^2) 做。

    O(n2)O(n^2) 复杂度内,我们还可以算出 tt 个点构成的、满足所有点都在 11tt 路径上的 DAG 数量,设为 gtg_t

    对于 kk 更小的情况,考虑在 gkg_k 的基础上增加点,使得仍然只有这 kk 个点满足要求。

    将点划分为 33 类:

    • 11 类点,表示在 11nn 的路径上(即在我们钦定的 kk 个点之中);
    • 22 类点,表示能从 11 到达的、但不是 11 类点的点;
    • 33 类点,表示不能从 11 到达的点。

    opiop_i 表示这 nn 个点类型构成的序列,其中 op1=opn=1op_1=op_n=1。我们还需要再 opop 中分配 k2k-211,以及若干个 2233。对于每一种分配方式,我们计算所有额外边(不是 11 类和 11 类的连边)的连接方式,乘上 gkg_k,加到 anskans_k 中。

    对于每个点,我们往前连边。

    • 11 类点:可以往编号比他小的 33 类点连边;
    • 22 类点:可以往编号比他小的 112233 类点连边,且必须往至少一个 1122 类点连边;
    • 33 类点:可以往编号比他小的 33 类点连边。

    发现什么?33 类点可以往其后面所有点连边。所以假设所有的 33 类点在 p1p_1p2p_2\cdotspzp_z 处,可以产生的贡献为 2i=1znpi2^{\sum_{i=1}^z n-p_i}

    因此我们可以 DP 求出所有的贡献之和,然后将 33 类点删掉,只考虑 1122 类点之间的贡献。这也可以 O(n2)O(n^2) 暴力。

    整体时间复杂度为 O(n2)O(n^2),足以通过本题。

    #include<bits/stdc++.h>
    #define int long long
    #define ffor(i,a,b) for(int i=(a);i<=(b);i++)
    #define roff(i,a,b) for(int i=(a);i>=(b);i--)
    using namespace std;
    const int MAXN=2000+10;
    int n,MOD,dp[MAXN][MAXN],C[MAXN][MAXN],pw[MAXN*MAXN],ans[MAXN];
    int mul[MAXN][MAXN],f[MAXN][MAXN],g[MAXN]; 
    signed main() {
    	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    	cin>>n>>MOD;
    	pw[0]=1; ffor(i,1,n*n) pw[i]=pw[i-1]*2%MOD;
    	ffor(i,0,n) {
    		C[i][0]=1;
    		ffor(j,1,i) C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD;	
    	}
    	dp[1][0]=1;
    	ffor(i,2,n) ffor(j,0,i-1) {
    		int mul=dp[i-1][j];
    		if(j) mul=(mul+dp[i-1][j-1])%MOD;
    		dp[i][j]=mul*(pw[i-j-1]-1)%MOD;
    	}
    	ffor(i,2,n) ffor(j,0,i) g[i]=(g[i]+dp[i][j]*(1-2*(j&1)))%MOD;
    	mul[n][0]=1;
    	roff(i,n-1,2) ffor(j,0,n) {
    		mul[i][j]=mul[i+1][j];
    		if(j) mul[i][j]=(mul[i][j]+mul[i+1][j-1]*pw[n-i])%MOD;
    	}
    	f[1][0]=1;
    	ffor(i,1,n) ffor(j,(i==1),n-i) {
    		f[i][j]=f[i-1][j],ans[i]=(ans[i]+mul[2][n-i-j]*f[i][j])%MOD;
    		if(j) f[i][j]=(f[i][j]+f[i][j-1]*(pw[i+j-1]-1))%MOD;
    	}
    	ffor(i,2,n) ans[i]=ans[i]*g[i]%MOD;
    	ans[0]=pw[n*(n-1)/2];
    	ffor(i,2,n) ans[0]=(ans[0]-ans[i])%MOD;
    	ffor(i,0,n) cout<<(ans[i]%MOD+MOD)%MOD<<' ';
    	return 0;
    }
    
    • 1

    信息

    ID
    12218
    时间
    2000ms
    内存
    1024MiB
    难度
    7
    标签
    递交数
    0
    已通过
    0
    上传者