zoukankan      html  css  js  c++  java
  • ACM-ICPC实验室周赛2020.3.13(2019山东)

    A.Calendar

    题意:

    每一年12个月,每个月30天,每星期只有5天,问下一个日期是星期几。

    题解:

    直接忽略年和月,算天数就可以得到答案。

    #include<bits/stdc++.h>
    using namespace std;
    typedef int ll;
    int T;
    int year,month,day;
    int year1,month1,day1;
    string s[6]={"Monday","Tuesday","Wednesday","Thursday","Friday"};
    unordered_map<string,int> pos;
    int main () {
        scanf("%d",&T);
        string ss;
        for (int i=0;i<5;i++)
            pos[s[i]]=i;
        while (T--) {
            scanf("%d%d%d",&year,&month,&day);
            cin>>ss;
            scanf("%d%d%d",&year1,&month1,&day1);
            int t1=day;
            int t2=day1;
            int tmp=pos[ss];
            if (t1<=t2) 
                tmp=(tmp+(t2-t1)%5)%5;
            else 
                tmp=(tmp+5-(t1-t2)%5)%5; 
            printf("%s
    ",s[tmp].c_str());
    
        }
        return 0;
    }
    View Code

    B.Flipping Game

    题意:

    给你一串灯泡的初始状态和最终状态,然后你可以进行K次操作,每次操作可以选择任意M个灯泡来改变他们的状态,询问你在K次操作后有多少种方案可以把灯泡从初始状态变成最终状态。

    题解:

    动态规划。

    先预处理计算好范围内所有组合数的值,然开一个二维DP数组,表示第i步操作后有j个不同的状态,k表示第i+1次操作后有k个不同的状态会被修正,推出状态转移方程:

    dp[i+1][j][j-k+M-k]+=dp[i][j]*c[j][k]*c[N-j][M-k]

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=105;
    const int mod=998244353;
    typedef long long ll;
    ll dp[maxn][maxn];
    ll c[maxn][maxn];
    //表示第i步有j个不同的状态的方案数 
    string s,t;
    int main () {
        int T;
        scanf("%d",&T);
        for (int i=0;i<maxn;i++)
            c[i][0]=1;
        for (int i=1;i<maxn;i++)
            c[i][i]=1;
        for (int i=2;i<maxn;i++) 
            for (int j=1;j<i;j++)
                c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
        while (T--) {
            int N,M,K;
            scanf("%d%d%d",&N,&K,&M);
            cin>>s>>t;
            int ans=0;
            for (int i=0;i<s.length();i++)
                ans+=s[i]!=t[i];
            memset(dp,0,sizeof(dp));
            dp[0][ans]=1;
            for (int i=0;i<=K;i++)
                for (int j=0;j<=N;j++) 
                    for (int k=0;k<=M;k++) 
                        if (k<=j) {
                            dp[i+1][j-k+M-k]+=dp[i][j]*c[j][k]%mod*c[N-j][M-k]%mod;
                            dp[i+1][j-k+M-k]%=mod;
                        }
            printf("%lld
    ",dp[K][0]);    
        } 
        return 0;
    }
    View Code

    C.Wandering Robot

    题意:

    给你一组机器人的指令,并执行K次,询问机器人在执行指令的过程中所能抵达的最远曼哈顿距离。

    题解:

    考虑两种情况:

    • 机器人在第一组指令就达到了最远距离
    • 机器人在第K-1组指令后达到了最远距离

    以此进行模拟即可。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=105;
    typedef long long ll;
    string s;
    int T;
    int N,K;
    ll x,y;
    int main () {
        scanf("%d",&T);
        while (T--) {
            scanf("%d %d",&N,&K);
            cin>>s;
            x=0;
            y=0;
            ll Max=-1;
            for (int i=0;i<N;i++) {
                if (s[i]=='U') y++;
                if (s[i]=='D') y--;
                if (s[i]=='L') x--;
                if (s[i]=='R') x++;
                Max=max(Max,abs(x)+abs(y));
            } 
            x*=K-1;
            y*=K-1;
            for (int i=0;i<N;i++) {
                if (s[i]=='U') y++;
                if (s[i]=='D') y--;
                if (s[i]=='L') x--;
                if (s[i]=='R') x++;
                Max=max(Max,abs(x)+abs(y));
            }
            printf("%lld
    ",Max);
        }
        return 0;
    }
    View Code

    D.Game On a Graph

    题意:

    有两个队的人,他们轮流对一个图进行删边,可以选择自己想删的边。当删完边后这个图变得不再连通了,就会输掉比赛。

    给出图的信息,询问哪个队会赢下比赛。

    题解:

    不断进行最优选择的情况下,必定是当图只剩下N-1条边的时候删边的队伍输掉比赛,找到那个编号的人所在的队伍,输出另一个队即可。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e6+14;
    string s;
    int N,M;
    int main () {
        int T;
        scanf("%d",&T);
        while (T--) {
            int len;
            scanf("%d",&len);
            cin>>s;
            scanf("%d%d",&N,&M);
            int x,y;
            for (int i=0;i<M;i++) scanf("%d%d",&x,&y);
            int tmp=(M-N+1)%len;
            if (s[tmp]=='1') printf("2
    ");
            else printf("1
    ");
        }
        return 0;
    } 
    View Code

    E.BaoBao Loves Reading

    题意:

    书桌上有一些书,给出一个书籍编号序列,代表要读书的顺序,当前要读的书在桌子上时就直接读,不再桌子上时就去书架上拿,书桌有一个容量,当书桌满的时候需要把最早读的那本书放到书架上。询问在书桌容量从1到N的时候各需要从书架上拿几次书。

    题解:

    推出两本相同的书之间有多少本不同的书,这个数量如果大于K(当前书桌容量)就需要从书架上拿书。

    考虑用线段树实现这个过程,开一个前驱数组,记录下每本书上次出现的位置,每次统计数量的时候先把它上次的贡献剪掉,再更新数量。‘

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e5+10;
    int a[maxn];
    int b[maxn];
    int pre[maxn];
    int T;
    int N;
    struct node {
        int l;
        int r;
        int sum;
    }segTree[maxn*40];
    
    void build (int i,int l,int r) {
        segTree[i].sum=0;
        segTree[i].l=l;
        segTree[i].r=r;
        if (l==r) return;
        int mid=(l+r)>>1;
        build(i<<1,l,mid);
        build(i<<1|1,mid+1,r);
    }
    
    
    void update (int i,int t,int b) {
        if (segTree[i].l==t&&segTree[i].r==t) {
            segTree[i].sum+=b;
            return;
        }
        int mid=(segTree[i].l+segTree[i].r)>>1;
        if (t<=mid) update(i<<1,t,b);
        else update(i<<1|1,t,b);
        segTree[i].sum=segTree[i<<1].sum+segTree[i<<1|1].sum;
    } 
    
    
    int query (int i,int l,int r) {
        if (segTree[i].l==l&&segTree[i].r==r) {
            return segTree[i].sum;
        }
        int mid=(segTree[i].l+segTree[i].r)>>1;
        if (r<=mid) 
            return query(i<<1,l,r);
        if (l>mid) 
            return query(i<<1|1,l,r);
        return query(i<<1,l,mid)+query(i<<1|1,mid+1,r);
    }
    
    
    int main () {
        scanf("%d",&T);
        while (T--) {
            scanf("%d",&N);
            memset(pre,0,sizeof(pre));
            memset(b,0,sizeof(b));
            build(1,1,N*4);
            for (int i=1;i<=N;i++) 
                scanf("%d",&a[i]);
            for (int i=1;i<=N;i++) {
                if (!pre[a[i]]) {
                    update(1,i,1);
                    pre[a[i]]=i;
                    continue;
                }
                update(1,pre[a[i]],-1);
                update(1,i,1);
                b[query(1,pre[a[i]],i)]++;
                pre[a[i]]=i;
            }
            for (int i=1;i<=N;i++) {
                if (i!=1) printf(" ");
                b[i]+=b[i-1];
                printf("%d",N-b[i]);
            }
            printf("
    ");
        }
        return 0;
    }
    View Code

    L.Median

    题意:

    给出一组序列的大小以及里面的数的一些大小关系,询问哪些数有可能成为中位数。

    题解:

    根据这些大小关系建立一个有向图,跑一遍floyd算法。

    当以下情况出现时,这个序列是不合法的:

    • 出现自环,即A比A大
    • 出现双向边,即A比B大的同时B比A大

    合法序列的前提下,统计每个数一定比自己大的数的数目和一定比自己小的数的数目,如果都小于N/2,那么这个数可以作为中位数。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=105;
    const int inf=1e9;
    int T;
    int N,M;
    int g[maxn][maxn];
    int a[maxn];
    int l[maxn];
    int r[maxn];
    void floyd () {
        for (int k=1;k<=N;k++) {
            for (int i=1;i<=N;i++) {
                for (int j=1;j<=N;j++) 
                    g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
            }
        }
    }
    int main () {
        int T;
        scanf("%d",&T);
        while (T--) {
            scanf("%d%d",&N,&M);
            memset(a,0,sizeof(a));
            memset(l,0,sizeof(l));
            memset(r,0,sizeof(r));
            for (int i=1;i<=N;i++) 
                for (int j=1;j<=N;j++)
                    g[i][j]=inf;
            for (int i=0;i<M;i++) {
                int x,y;
                scanf("%d%d",&x,&y);
                g[x][y]=1;
            }
            int flag=0;
            floyd();
            for (int i=1;i<=N;i++) 
                for (int j=1;j<=N;j++) 
                    if (g[i][j]!=inf&&g[j][i]!=inf)
                    flag=1;
            if (flag) {
                for (int i=0;i<N;i++)
                    printf("0");
                printf("
    ");
                continue;
            }
            
            for (int i=1;i<=N;i++) {
                for (int j=1;j<=N;j++) {
                    if (g[i][j]!=inf) l[i]++,r[j]++;
                }
            }
            for (int i=1;i<=N;i++) {
                if (l[i]<=N/2&&r[i]<=N/2) a[i]=1;
            }
            for (int i=1;i<=N;i++) printf("%d",a[i]);
            printf("
    ");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    SQLite Select语句的意外发现
    和一个经理人谈话的经典语句
    [转]如何动态增长一个数组的大小
    [转]Spring AOP中文教程
    为Wildfish框架增加方法调用日志[Aspectsharp]
    第四周学习心得
    《大道至简:软件工程实践者的思想》观后感
    第三周学习心得
    暑假第一周Java学习心得
    第二周学习心得
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/12493664.html
Copyright © 2011-2022 走看看