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 (n−1)k−m∗(m−1)!∗i=1∏mai。
设 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]);
}