2020.3.13实验室周赛题解(2019山东)

Posted zhanglichen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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

 

以上是关于2020.3.13实验室周赛题解(2019山东)的主要内容,如果未能解决你的问题,请参考以下文章

2019山东省赛B - Flipping Game ZOJ - 4114 题解

2019山东省赛K - Happy Equation ZOJ - 4123 题解

双周赛 52,单周赛 241 题解

[ICPC训练联盟周赛1] CTU Open Contest 2019

AcWing第23场周赛题解

2020-3-14 acm训练联盟周赛Preliminaries for Benelux Algorithm Programming Contest 2019 解题报告+补题报告