联考20200618 T1 墨水大师
题目:
分析:
考虑树的情况,把根的颜色确定之后剩下的颜色只需要与父亲不同就好了,答案为\(C(C-1)^{n-1}\)
考虑环的情况,答案需要减去终点和起点颜色相同的情况,强行合并起点终点答案为\(C(C-1)^{n-1}\),但是发现这样多减了终点和倒数第二个点相同的情况。。。
考虑容斥
假设一个环的长度为\(n\),答案为\(\sum_{i=1}^{n}(-1)^{i-1}C(C-1)^{n-i}\)
发现这是一个等比数列,当我们知道C之后就可以求出任意环大小的答案
运用一个有趣的性质
一个\(n\)个点的仙人掌最多由\(\sqrt{n}\)种大小的环组合起来
于是预处理仙人掌的环,然后对于每一个\(C\)暴力计算即可
复杂度\(O(q\sqrt{n}logMOD)\),\(log\)是求逆元
这玩意还被卡我无话可说,不优化了(2333
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define maxn 400005
#define MOD 998244353
using namespace std;
inline int getint()
{
int num=0,flag=1;char c;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
return num*flag;
}
int n,m,q;
int fir[maxn],nxt[maxn],to[maxn],cnt;
int dfn[maxn],low[maxn],tim,stk[maxn],tp;
int b[maxn];
int Sz[maxn],Tim[maxn],cur;
inline void newnode(int u,int v)
{to[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt;}
inline void tarjan(int u)
{
dfn[u]=low[u]=++tim,stk[++tp]=u;
for(int i=fir[u];i;i=nxt[i])
if(!dfn[to[i]])
{
tarjan(to[i]),low[u]=min(low[u],low[to[i]]);
if(low[to[i]]>=dfn[u])
{
int num=0,x;
do{x=stk[tp--],num++;}while(x!=to[i]);
b[num]++;
}
}
else low[u]=min(low[u],dfn[to[i]]);
}
inline int ksm(int num,int k)
{
int ret=1;
for(;k;k>>=1,num=1ll*num*num%MOD)if(k&1)ret=1ll*ret*num%MOD;
return ret;
}
inline int calc(int N,int C)
{
int P=MOD-ksm(C-1,MOD-2),A=ksm(C-1,N);
P=1ll*(1-ksm(P,N))*ksm(1-P,MOD-2)%MOD;
return 1ll*A*P%MOD;
}
int main()
{
n=getint(),m=getint(),q=getint();
for(int i=1;i<=m;i++)
{
int u=getint(),v=getint();
newnode(u,v),newnode(v,u);
}
tarjan(1);
for(int i=1;i<=n;i++)if(b[i])Sz[++cur]=i,Tim[cur]=b[i];
while(q--)
{
int C=getint();
int tmp=1;
for(int i=1;i<=cur;i++)
tmp=1ll*tmp*ksm(calc(Sz[i],C),Tim[i])%MOD;
printf("%lld\n",1ll*C*tmp%MOD);
}
}