PPFish-NOIP模拟题2015题解

来源:互联网 发布:汕头大学网络教育 编辑:程序博客网 时间:2024/05/19 01:10

数据铁到std都过不去…

话说暴力真的可以出奇迹!:)


目录

    • Food Chain
    • So many prefix
    • Illegal Motor


1.Food Chain

1·1/2
1·2/2

  • 因为有k-1条边,所以只可能是一棵树,即根节点是最高营养级的物种。bfs按营养级一层一层搜,之后再从叶子节点向上传递能量就行了。
  • 这里的队其实有点像栈,bfs入队后并不出来,只是head头指针向后移动,最后是像栈一样弹出的。
  • 看到数据量果断开启读入优化...
#include <cstdio>#include <iostream>using namespace std;const int MAXN=2000005;const long long P=32416190071;long long w[MAXN];int s[MAXN],yita[MAXN],h[MAXN],no,fa[MAXN];bool use[MAXN];struct line{    int to,next;}edge[MAXN];inline int read(){    char c; int x;    while(c=getchar(),c<'0' || '9'<c);    x=c-'0';    while(c=getchar(),'0'<=c && c<='9')        x=x*10+c-'0';    return x;}inline void add(int u,int v){    edge[++no].next=h[u];    h[u]=no;    edge[no].to=v;}int main(){#ifndef ONLINE_JUDGE    freopen("Chain.in","r",stdin);    freopen("Chain.out","w",stdout);#endif    int n=read(),tmpx,tmpy,cnt=0,head=0,tail=0,now,pos;    for(int i=1;i<n;++i){        tmpx=read(),tmpy=read();        fa[tmpy]=tmpx;        add(tmpx,tmpy);        yita[tmpy]=read();        use[tmpy]=true;    }    for(int i=1;i<=n;++i)        w[i]=read();    for(int i=1;i<=n;++i){        if(!use[i]){            pos=i;            s[++tail]=i;            break;        }    }    while(head<tail){        now=s[++head];        if(!h[now]) ++cnt;        else{            for(int i=h[now];i;i=edge[i].next)                s[++tail]=edge[i].to;        }    }    while(tail){        now=s[tail];        --tail;        w[fa[now]]=(w[fa[now]]+w[now]*yita[now]%P)%P;    }    cout<<cnt<<endl<<w[pos]<<endl;#ifndef ONLINE_JUDGE    fclose(stdin);    fclose(stdout);#endif    return 0;}

2. So many prefix?

2·1/2
2·2/2

  • dp+kmp.
  • 考虑kmp中的f[i],代表最大的k(k!=i)使c[1]c[2]…c[k]==c[i–k +1]c[i–k]…c[i]成立,那么我们设dp[i]代表以i为前缀,即s[1]s[2]…s[i],内所有偶数子串出现的次数(包含本身)。
  • 于是得到状态转移方程:
    dp(i)={1+dp[f[i]]dp[f[i]]i%2==0 i%2==1
#include <cstdio>#include <cstring>#include <iostream>using namespace std;const int MAXN=200005;int m,f[MAXN];long long dp[MAXN];char c[MAXN];void getfail(){    m=strlen(c);    int j;    for(int i=1;i<m;++i){        j=f[i];        while(c[i]!=c[j] && j) j=f[j];        f[i+1]= c[i]==c[j] ? j+1:0;    }}long long work(){    long long ans=0;    for(int i=1;i<=m;++i){        if(~i&1) dp[i]=1;        dp[i]+=dp[f[i]];        ans+=dp[i];    }    return ans;}int main(){#ifndef ONLINE_JUDGE    freopen("Prefix.in","r",stdin);    freopen("Prefix.out","w",stdout);#endif    scanf("%s",c);    getfail();    cout<<work()<<endl;#ifndef ONLINE_JUDGE    fclose(stdin);    fclose(stdout);#endif    return 0;}

3.Illegal Motor

3·1/2
3·2/2

  • 很裸的分层图问题,建k+1个图。若u,v间有连边,则第i个的u和第i+1个图v’连一条0边(因为是无向图,所以v和u’也要连)。
  • 之后从第一个图的s跑最短路(要用dijsktra,SPFA会被卡死…),ans=min{dis[ti]}。
#include <cstdio>#include <queue>using namespace std;const int MAXN=10005*11,MAXM=50005*21<<1,INF=~0U>>1;int head[MAXN],cnt,n,m,k,s,t;bool use[MAXN];struct list{    int dis,x;    list(){dis=INF;}    friend bool operator> (const list &a,const list &b){        return a.dis>b.dis;    }}node[MAXN];priority_queue<list,vector<list>,greater<list> > q;struct line{    int to,next,len;}edge[MAXM];inline int read(){    char c; int x;    while(c=getchar(),c<'0' || '9'<c);    x=c-'0';    while(c=getchar(),'0'<=c && c<='9')        x=x*10+c-'0';    return x;}inline void add(int u,int v,int w){    edge[++cnt].next=head[u];    head[u]=cnt;    edge[cnt].to=v;    edge[cnt].len=w;}void build(){    int x,y,w;    for(int i=1;i<=m;++i){        x=read(),y=read(),w=read();        for(int j=0;j<k;++j){            add(x+n*j,y+n*j,w);            add(y+n*j,x+n*j,w);            add(x+n*j,y+n*(j+1),0);            add(y+n*j,x+n*(j+1),0);        }        add(x+n*k,y+n*k,w);        add(y+n*k,x+n*k,w);    }}void dijsktra(){    for(int i=1;i<=n*(k+1);++i)        node[i].x=i;    node[s].dis=0;    q.push(node[s]);    list tmp;    int u,v,w;    while(q.size()){        tmp=q.top();        q.pop();        u=tmp.x;        if(!use[u]){            use[u]=true;            for(int i=head[u];i;i=edge[i].next){                v=edge[i].to,w=edge[i].len;                if(node[v].dis>node[u].dis+w){                    node[v].dis=node[u].dis+w;                    q.push(node[v]);                }            }        }    }}int main(){#ifndef ONLINE_JUDGE    freopen("Motor.in","r",stdin);    freopen("Motor.out","w",stdout);#endif    n=read(),m=read(),k=read();    s=read(),t=read();    build();    dijsktra();    int ans=INF;    for(int i=0;i<=k;++i)        ans=min(ans,node[t+n*i].dis);    printf("%d",ans);#ifndef ONLINE_JUDGE    fclose(stdin);    fclose(stdout);#endif    return 0;}

ps:谁知道第一段代码宏语句为啥红了…:(

0 0