NOMURA Programming Competition 2020

D - Urban Planning
( i , P i ) (i,P_i) (i,Pi)看做一条从 i i i连向 P i P_i Pi的有向边(当 P i = − 1 P_i=-1 Pi=1则视为点 i i i没有出边),则该图满足:在同一连通块中出度为 0 0 0的点的个数 ≤ 1 \le1 1(可以自己尝试用数学归纳法证明这条性质)。

将连通块中存在 0 0 0个出度为 0 0 0的点的连通块称为 零 连 通 块 零连通块
将连通块中存在 1 1 1个出度为 0 0 0的点的连通块称为 一 连 通 块 一连通块

如果没有 P i = − 1 P_i=-1 Pi=1的点,显然所有连通块都为 零 连 通 块 零连通块 ,对于一张这样的图,需要构建的边数为 n − 零 连 通 块 的 数 量 n-零连通块的数量 n

考虑对 零 连 通 块 零连通块 计数,最后用总的答案减去它。

对于一个已经确定的 零 连 通 块 零连通块 ,考虑将若干个 一 连 通 块 一连通块 与它相连,得到的仍然是 零 连 通 块 零连通块 ,因此这部分的数量不会改变。

考虑新构成的零连通块,它由若干个 一 连 通 块 一连通块 按顺序排列而成。设 m m m 一 连 通 块 一连通块 集合 a 1 , a 2 , . . . , a m a_1,a_2,...,a_m a1,a2,...,am a i a_i ai为第 i i i 一 连 通 块 一连通块 的点数)。

贡献为 ( n − 1 ) k − m ∗ ( m − 1 ) ! ∗ ∏ i = 1 m a i (n-1)^{k-m}*(m-1)!*\prod \limits_{i=1}^ma_i (n1)km(m1)!i=1mai

d p i , j dp_{i,j} dpi,j表示前 i i i个连通块中选了 j j j 一 连 通 块 一连通块 组成一个 零 连 通 块 零连通块 的贡献和,转移即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5005,mod=1e9+7;
int n,k,f[N],s[N],si[N],a[N],dp[N];
int getf(int x){return f[x]==x?x:f[x]=getf(f[x]);}
ll ans;
vector<int>v;
ll qpow(ll a,ll n)
{
    ll ans=1;
    for(;n;n>>=1,a=a*a%mod)if(n&1) ans=ans*a%mod;
    return ans;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),f[i]=i;
    for(int i=1;i<=n;i++) if(a[i]!=-1) f[getf(i)]=getf(a[i]);
    for(int i=1;i<=n;i++) if(a[i]==-1) s[getf(i)]++;
    for(int i=1;i<=n;i++) si[getf(i)]++;
    for(int i=1;i<=n;i++)
        if(f[i]==i)
        {
            if(s[i]==0) ans++;
            else v.push_back(si[i]);
        }
    k=v.size();
    dp[0]=1;
    for(int i=0;i<k;i++)
        for(int j=i+1;j>=1;j--)
    {
        dp[j]=(dp[j]+(ll)dp[j-1]*v[i]%mod*max(1,j-1)%mod)%mod;
    }
    ans=ans*qpow(n-1,k)%mod;
    for(int i=2;i<=k;i++) ans=(ans+qpow(n-1,k-i)*dp[i])%mod;
    for(int i=0;i<k;i++) ans=(ans+qpow(n-1,k-1)*(v[i]-1)%mod)%mod;
    ans=n*qpow(n-1,k)-ans;
    ans=(ans%mod+mod)%mod;
    printf("%lld\n",ans);
}
//(m-1)!*a[1]*a[2]*...*a[m] * (n-1)^(k-m)

E - Binary Programming
没空写了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
int n,a,b,c;
char s[N];
int main()
{
    scanf("%s",s+1);
    n=strlen(s+1);
    for(int i=1;i<=n;i++) if(s[i]=='0') b++;
    ll ans=0;
    for(int i=1;i<=n;i++)
        if(s[i]=='0') a++,b--;
        else
        {
            c++;
            if(s[i+1]=='1'){ans+=a+b+1;i++;c++;continue;}
            if(i&1)
                ans+=a/2+1+b;
            else ans+=(a+1)/2+b;
        }
    while(c)
    {
        c--;ans+=(c+1)/2;
    }
    printf("%lld\n",ans);
}

F - Sorting Game
没空写了。

#include<bits/stdc++.h>
using namespace std;
const int N=5005,mod=1e9+7;
typedef long long ll;
int n,m,dp[N][N];
int main()
{
    //int p[N];p[0]=1;for(int i=1;i<N;i++) p[i]=(p[i-1]<<1)%mod;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++) dp[0][i]=1;
    for(int i=1;i<=n;i++)
        for(int j=1,sum=0;j<=m;j++)
    {
        dp[i][j]=(dp[i][j]+(ll)dp[i-1][j]*(j+1)+sum)%mod;
        sum=(sum*2%mod+(ll)dp[i-1][j]*j)%mod;
        //dp[i][j]=(dp[i][j]+(ll)(dp[i][j-1]-(ll)dp[i-1][j-1]*j%mod+mod)%mod*2%mod+(ll)dp[i-1][j-1]*(j-1))%mod;
        /*
        for(int k=2;k<=j;k++)
            dp[i][j]=(dp[i][j]+(ll)dp[i-1][j-k+1]*(j-k+1)%mod*p[k-2]%mod)%mod;
        */
    }
    printf("%d\n",dp[n][m]);
}

猜你喜欢

转载自blog.csdn.net/Huah_2018/article/details/106590345