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]);
}

 

满满的智障气息.

 

posted @ 2017-06-16 17:22  SiriusRen  阅读(242)  评论(0编辑  收藏  举报