首页 > 代码库 > 暑期测试训练3

暑期测试训练3

1.Codeforces 20C

spfa算法的简单题,在这个过程中多了一个记录连接最短路径上的前一个节点的位置的数组,然后将这个数组逆向输出

在这道题目中,我路径数组范围居然忘记*2了,结果一直报错,找了好久,%>_<%

#include <iostream>#include <cstdio>#include <queue>#include <cstring>using namespace std;#define N 100010#define LL long longLL dp[N];int first[N],visit[N],k,n,f[N],r[N];struct Path{    int y,d,next;}path[2*N];void add(int a,int b,int c){    path[k].y=b,path[k].d=c,path[k].next=first[a];    first[a]=k;    k++;}bool spfa(int src){    bool judge=false;    memset(dp,-1,sizeof(dp));    memset(f,0,sizeof(f));    memset(visit,0,sizeof(visit));    queue<int> q;    dp[src]=0,visit[src]=1;    q.push(src);    while(!q.empty()){        int u=q.front();        q.pop();        visit[u]=0;        for(int i=first[u];i!=-1;i=path[i].next){            if(dp[path[i].y]==-1||dp[path[i].y]>dp[u]+path[i].d){                dp[path[i].y]=dp[u]+path[i].d;                f[path[i].y]=u;                if(!visit[path[i].y])                {                    visit[path[i].y]=1,q.push(path[i].y);                    if(path[i].y==n)                        judge=true;                }            }        }    }    return judge;}int main(){    int m,a,b,c;    while(scanf("%d%d",&n,&m)!=EOF){        k=0;        memset(first,-1,sizeof(first));        for(int i=0;i<m;i++){            scanf("%d%d%d",&a,&b,&c);            add(a,b,c);            add(b,a,c);        }        if(!spfa(1)){            printf("-1\n");            continue;        }        int cnt=0;        for(int i=n;i!=0;i=f[i])            r[cnt++]=i;        for(int i=cnt-1;i>=1;i--)            printf("%d ",r[i]);        printf("%d\n",r[0]);    }    return 0;} 
View Code

2.CodeForces 295B
这道题需计算所有节点对的最短路径和,所以用floyd算法,这里是不断删除节点,对于一个图来说,不断添加节点总是比不断删除节点要简单的多的,所以这道题逆向

考虑,从最后往前面不断加入节点

#include <iostream>#include<cstdio>#include<cstring>#include <algorithm>using namespace std;#define N 502#define LL long longint n,dp[N][N],v[N];LL ans[N];void floyd(int k){    for(int i=1;i<=n;i++){        for(int j=1;j<=n;j++){            dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]);        }    }}LL query(int t){    LL sum=0;    for(int i=n;i>=t;i--)        for(int j=n;j>=t;j--)            sum+=dp[v[i]][v[j]];    return sum;}int main(){    while(scanf("%d",&n)!=EOF){        for(int i=1;i<=n;i++)            for(int j=1;j<=n;j++)                scanf("%d",&dp[i][j]);        for(int i=1;i<=n;i++) scanf("%d",&v[i]);        for(int i=n;i>=1;i--){            floyd(v[i]);            ans[i]=query(i);        }        for(int i=1;i<=n-1;i++)            printf("%I64d ",ans[i]);        printf("%I64d\n",ans[n]);    }    return 0;}
View Code

3.SPOJ MULTQ3
这道题目特别容易超时。。。我就不吐槽我自己一会提交成功一会TLE了,感觉要看运气~~

这道题目主要考虑在pushdown上面的修改,因为是否为3的整数倍,中间有余1和余2两种情况要进行考虑

另外我们增添两个数组来保存余1和余2的个数,当然你也可以考虑用2维数组,这里情况比较少,多建几个数组也不是很麻烦

#include <iostream>#include <cstdio>#include <cstring>using namespace std;#define N 100005int sum1[4*N],sum2[4*N],sum3[4*N],a[N],add[4*N];void update(int cur){    sum1[cur]=sum1[cur<<1]+sum1[cur<<1|1];    sum2[cur]=sum2[cur<<1]+sum2[cur<<1|1];    sum3[cur]=sum3[cur<<1]+sum3[cur<<1|1];}void build(int cur,int x,int y){    add[cur]=0;    int mid=(x+y)/2,ls=cur<<1,rs=cur<<1|1;    if(x==y){        sum1[cur]=1;        sum2[cur]=0;        sum3[cur]=0;        return;    }    build(ls,x,mid);    build(rs,mid+1,y);    update(cur);}void pushdown(int cur,int x,int y){    int ls=cur<<1,rs=cur<<1|1;    if(add[cur]%3!=0)    {        add[ls]+=add[cur],add[rs]+=add[cur];        if(add[cur]%3==1){            int temp=sum1[ls];            sum1[ls]=sum3[ls];            sum3[ls]=sum2[ls];            sum2[ls]=temp;            temp=sum1[rs];            sum1[rs]=sum3[rs];            sum3[rs]=sum2[rs];            sum2[rs]=temp;        }        else if(add[cur]%3==2){            int temp=sum2[ls];            sum2[ls]=sum3[ls];            sum3[ls]=sum1[ls];            sum1[ls]=temp;            temp=sum2[rs];            sum2[rs]=sum3[rs];            sum3[rs]=sum1[rs];            sum1[rs]=temp;        }        add[cur]=0;    }}void change(int cur,int x,int y,int s,int t,int v){    int mid=(x+y)/2,ls=cur<<1,rs=cur<<1|1;    if(x>=s&&y<=t){        int temp;        temp=sum1[cur];        sum1[cur]=sum3[cur];        sum3[cur]=sum2[cur];        sum2[cur]=temp;        add[cur]+=v;        return;    }    pushdown(cur,x,y);    if(mid>=s) change(ls,x,mid,s,t,v);    if(mid+1<=t) change(rs,mid+1,y,s,t,v);    update(cur);}void query(int cur,int x,int y,int s,int t,int &ans){    int mid=(x+y)/2,ls=cur<<1,rs=cur<<1|1;    if(x>=s&&y<=t){        ans+=sum1[cur];        return;    }    pushdown(cur,x,y);    if(mid>=s) query(ls,x,mid,s,t,ans);    if(mid+1<=t) query(rs,mid+1,y,s,t,ans);}int main(){    int n,q,log,a,b;    while(scanf("%d%d",&n,&q)!=EOF){        build(1,0,n-1);        for(int i=0;i<q;i++){            scanf("%d",&log);            if(log==0){                scanf("%d%d",&a,&b);                change(1,0,n-1,a,b,1);            }            else{                scanf("%d%d",&a,&b);                int ans=0;                query(1,0,n-1,a,b,ans);                printf("%d\n",ans);            }        }    }    return 0;}
View Code

4.CodeForces 4C
最基础的Map题,熟悉一下map的简单用法

#include <iostream>#include <cstdio>#include <map>using namespace std;#define N 100010int n;int main(){    map<string,int> a;    string s;    while(scanf("%d",&n)!=EOF){        cin>>s;        a[s]++;        if(a[s]>1){            cout<<s<<a[s]-1<<endl;        }        else cout<<"OK"<<endl;    }    return 0;}
View Code

5.SPOJ ROCK
Dp题,据说很简单~~~反正我做不出。。。还是太水了

这里dp[i]表示在前i段可以卖出的最大长度

在第j段后面砍一刀,如果砍出来的那一段甜的成分大于酸的成份,再进行

dp[i]=max(dp[i],dp[j]+i-j)的更新操作

每次一个i结束循环,都进行一下dp[i]=dp[i-1]的更新操作,保证时刻都能更新到最大值

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;#define N 203char ch[N];int dp[N],sum[N][2];int main(){    int T,n;    scanf("%d",&T);    while(T--){        memset(dp,0,sizeof(dp));        scanf("%d",&n);        //sum[0][0]=sum[0][1]=0;        for(int i=1;i<=n;i++)        {            cin>>ch[i];            sum[i][1]=sum[i-1][1];            sum[i][0]=sum[i-1][0];            sum[i][ch[i]-0]++;        }        for(int i=1;i<=n;i++){            dp[i]=dp[i-1];            for(int j=0;j<i;j++)                if(sum[i][1]-sum[j][1]>sum[i][0]-sum[j][0])                    dp[i]=max(dp[j]+i-j,dp[i]);        }        cout<<dp[n]<<endl;    }    return 0;}
View Code

6.SPOJ NITK06
居然拿第六题作为签到题,太可恶了。

简单讲一下,只要奇数位上的和等于偶数位上的和这个就成立了

#include <iostream>using namespace std;#define N 10005int a[N];int main(){    int T,n,odd,even;    cin>>T;    while(T--){        cin>>n;        odd=0,even=0;        for(int i=1;i<=n;i++)        {            cin>>a[i];            if(i%2==0) even+=a[i];            else odd+=a[i];        }        if(odd==even) cout<<"YES"<<endl;        else cout<<"NO"<<endl;    }    return 0;}
View Code