0616考试
T1
Problem 1. spread
Input file:spread.in
Output file:spread.out
Time limit:1 second
Memory limit:256 MB
Darrell 所在的国家有 N 个城市,共有 N 1 条输水管道连接它们,使得任意两个城市都可以通过这些
输水管道连接起来。
有一种破坏力极强的病毒被发现带入了境内,但不知道在哪个城市,现在已知如果病毒在 u 号城市爆发,
则其会随着输水管道向向周围的城市不断扩散,但因为一些原因,扩散的速度有可能不一致。
问题是,如果 u 号城市爆发病毒,则一段时间后可能的扩散情况有多少种?你需要对每个城市回答该问
题。(答案可能很大,你只需要输出取模 10
9
+ 7 的结果即可)。
Input
第 1 行,有 1 个整数 N,表示城市数目。
接下来 N 1 行,每行 2 个整数:u v,表示城市 u 和 v 之间有输水管道。
Output
输出 1 行,包含 N 个整数,第 i 个整数表示 i 号城市爆发病毒对应的答案。
Sample
spread.inspread.out
4
1 2
2 3
2 4
5 8 5 5
Note
样例中,如果 1 号城市爆发病毒,则可能的扩散情况有:[1],[1;2],[1;2;3],[1;2;4],[1;2;3;4],共 5 种。
如果 2 号城市爆发病毒,则可能的扩散情况有:[2],[2;1],[2;3],[2;4],[2;1;3],[2;3;4],[2;1;4],[2;1;3;4],共 8
种。
DP+换根
//By SiriusRen #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N=200500,mod=1000000007; int n,a[N],first[N],next[N],v[N],tot,xx,yy,f[N],g[N]; void add(int x,int y){v[tot]=y,next[tot]=first[x],first[x]=tot++;} void dfs(int x,int fa){ f[x]=1;int r=1; for(int i=first[x];~i;i=next[i])if(v[i]!=fa){ dfs(v[i],x);r=(1ll*r*f[v[i]])%mod; }f[x]=(f[x]+r)%mod; } int pow(int x,int y){ int r=1; while(y){ if(y&1)r=1ll*r*x%mod; x=1ll*x*x%mod,y>>=1; }return r; } void dfs2(int x,int fa){ for(int i=first[x];~i;i=next[i])if(v[i]!=fa){ g[v[i]]=((1ll*(g[x]-1+mod)%mod*pow(f[v[i]],mod-2)%mod+1)%mod*((f[v[i]]-1+mod)%mod)+1)%mod; dfs2(v[i],x); } } int main(){ freopen("spread.in","r",stdin); freopen("spread.out","w",stdout); memset(first,-1,sizeof(first)); scanf("%d",&n); for(int i=2;i<=n;i++)scanf("%d%d",&xx,&yy),add(xx,yy),add(yy,xx); dfs(1,0);g[1]=f[1];dfs2(1,0); for(int i=1;i<=n;i++)printf("%d ",(g[i]-1+mod)%mod); }
T2
Problem 2. sing
Input file:sing.in
Output file:sing.out
Time limit:1 second
Memory limit:256 MB
Darrell 在学唱歌。
Darrell 已经学会了一些发音技巧,比如刚唱完 u 号音符就可以接着唱 v 号音符。
因为一些特殊的原因,如果 Darrell 能够连续唱出 u1;u2;u3;:::;un,且 u1= u2,那么保证 u1到 un之间
至多有 5 种不同的音符。
Darrell 想自己编一首自己唱的歌,为了独特,他希望歌中不出现重复的音符,并且想让歌声中包含的音
符尽量多,所以,请你告诉他最多能唱多少个音符。
Input
第 1 行,包含 2 个整数:N M,分别表示 Darrell 会唱的音符数及已经掌握了的发音技巧数。
接下来 M 行,每行 2 个整数:u v,表示 Darrell 在唱完 u 后能够接着唱 v。
Output
输出 1 个整数,表示答案。
Sample
sing.insing.out
4 5
1 2
2 3
3 4
3 1
2 4
4
样例解释:可以连续唱出:3;1;2;4 的音符,所以最多为 4 个音符。
sing.insing.out
7 7
1 2
2 3
3 4
4 5
5 2
4 6
5 7
6
样例解释:可以连续唱出 1;2;3;4;5;7 的音符,并且无法不重复地唱出更多的音符,所有所以最多为 6
个音符
Tarjan+Topsort+next_permutation
//By SiriusRen #include <bits/stdc++.h> using namespace std; const int N=1000050; vector<int>vec[N];queue<int>q; int n,m,xx,yy,first[N],next[N],v[N],tot,cnt,T,mp[5][5],f[5],d[N][5],ans; int low[N],dfn[N],vis[N],stk[N],p[N],id[N],bl[N][5],sz[N],top,du[N],tmp[N],dis[N]; void add(int x,int y){v[tot]=y,next[tot]=first[x],first[x]=tot++;} void tarjan(int x){ dfn[x]=low[x]=++cnt,stk[++top]=x,vis[x]=1; for(int i=first[x];~i;i=next[i]) if(!dfn[v[i]])tarjan(v[i]),low[x]=min(low[x],low[v[i]]); else if(vis[v[i]])low[x]=min(low[x],dfn[v[i]]); if(low[x]==dfn[x]){T++;do vis[xx=stk[top--]]=0,bl[T][sz[T]]=xx,p[xx]=T,id[xx]=sz[T]++;while(xx!=x);} } int main(){ freopen("sing.in","r",stdin); freopen("sing.out","w",stdout); memset(first,-1,sizeof(first)); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++)scanf("%d%d",&xx,&yy),add(xx,yy); for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i); for(int i=1;i<=T;i++){ memset(mp,0,sizeof(mp)); for(int j=0;j<sz[i];j++) for(int k=first[bl[i][j]];~k;k=next[k]) if(p[v[k]]==i)mp[j][id[v[k]]]=1; for(int j=0;j<sz[i];j++)f[j]=j; do{ for(int j=0;j<sz[i];j++){ d[bl[i][f[0]]][f[j]]=max(d[bl[i][f[0]]][f[j]],j); if(!mp[f[j]][f[j+1]])break; } }while(next_permutation(f,f+sz[i])); } for(int i=1;i<=n;i++)for(int j=first[i];~j;j=next[j])if(p[v[j]]!=p[i])du[p[v[j]]]++; for(int i=1;i<=T;i++)if(!du[i])q.push(i); while(!q.empty()){ int t=q.front();q.pop(); for(int i=0;i<sz[t];i++)for(int j=0;j<sz[t];j++)if(i!=j) tmp[bl[t][j]]=max(tmp[bl[t][j]],dis[bl[t][i]]+d[bl[t][i]][j]); for(int i=0;i<sz[t];i++)dis[bl[t][i]]=max(dis[bl[t][i]],tmp[bl[t][i]]); for(int i=0;i<sz[t];i++) for(int j=first[bl[t][i]];~j;j=next[j])if(p[v[j]]!=t){ dis[v[j]]=max(dis[v[j]],dis[bl[t][i]]+1),du[p[v[j]]]--; if(!du[p[v[j]]])q.push(p[v[j]]); } } for(int i=1;i<=n;i++)ans=max(ans,dis[i]); printf("%d\n",ans+1); }
T3
Memory limit:256 MB
Darrell 在思考一道计算题。
给你一个尺寸为 1 N 的长条,你可以在上面切很多刀,要求竖直地切并且且完后每块的长度都是整数。
在这种限制下其实只有 N 1 个位置可以切。
对于一种切的方案,假如切完后每块的宽度分别是:w1;w2;w3;:::;w
k
(
∑
wi= N),那么该种方案对应
的完美值为:
k∏
i=1
w
2
i
那么问题来了,给出 M 个位置不能切(如果用 x 表示一个位置,那么切完该位置后长条变为 1 x 和
1 (N x) 两块),
那么所有合法切法对应的完美值的和是多少呢?(只需要输出模 10
9
+ 7 的结果)
Input
第 1 行,有 2 个整数:N M,表示长条的总长度及不能切的位置数
第 2 行,有 M 个整数:x1;x2;x3;:::;xM表示不能切的位置。
Output
输出 1 行,包含 1 个整数,表示满足要求的所有切法对应的完美值和。(对 10
9
+ 7 取模后的结果)
Sample
count.incount.out
3 1
2
13
样例解释:一共有两种切法(用切完后的块的宽度表示):1;2 和 3,则对应答案为:1 2
2
+ 3
2
= 13
count.incount.out
5 2
2 3
66
样例解释:一共有四种切法:1;3;1、1;4、4;1 和 5,则对应答案为:1 3
2
1+1 4
2
+4
2
1+5
2
= 66
count.incount.out
10 9
1 2 3 4 5 6 7 8 9
100
因为所有能切的位置都不能切,所以只有一种切法(就是不切):10,对应答案为:10
2
构造一发矩阵+矩阵快速幂
//By SiriusRen #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define int long long const int mod=1000000007,N=100050; int n,m,xx,a[N]; struct Matrix{int a[3][3];void init(){memset(a,0,sizeof(a));} void Ch(){a[0][0]=a[1][0]=a[1][2]=2,a[0][1]=a[0][2]=a[1][1]=a[2][0]=a[2][2]=1;} void Ch2(){a[0][0]=a[0][1]=a[0][2]=a[1][1]=a[2][2]=1,a[1][2]=2;} }cng,cng2,jy; Matrix operator*(Matrix a,Matrix b){ Matrix c;c.init(); for(int k=0;k<3;k++) for(int i=0;i<3;i++) for(int j=0;j<3;j++) (c.a[i][j]+=a.a[i][k]*b.a[k][j])%=mod; return c; } Matrix operator^(Matrix a,int b){ Matrix r;r.init();r.a[0][0]=r.a[1][1]=r.a[2][2]=1; while(b){ if(b&1)r=r*a; a=a*a,b>>=1; }return r; } signed main(){ freopen("count.in","r",stdin); freopen("count.out","w",stdout); scanf("%lld%lld",&n,&m); for(int i=1;i<=m;i++)scanf("%lld",&a[i]); jy.a[0][0]=1;cng.Ch(),cng2.Ch2(); for(int i=1;i<=m;i++)jy=(jy*(cng^(a[i]-a[i-1]-1)))*cng2; jy=jy*(cng^(n-a[m])); printf("%lld\n",jy.a[0][2]); }
满满的智障气息.