Codeforces Round #627 (Div. 3)题解

比赛链接:Codeforces Round #627 (Div. 3)

A. Yet Another Tetris Problem

题意

你在玩俄罗斯方块,给出一个数组a,a[i]表示第i堆俄罗斯方块的个数,你可以用n个2*1的小长条去填补它(高为2,宽为1),规则同我们平时玩的俄罗斯方块,一列满了就可以消了。问你这堆有没有可能全部消掉。

思维题,通过不断尝试易知只要该数组所有数的奇偶性相同就有可能消掉。
当时本着位运算快一点的想法,判断奇偶性用的 x&1 后面发现老是不行,原来要(x&1),括号包起来下。

代码

#include<bits/stdc++.h>
#define mem(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int inf=0x7f7f7f7f;
template<typename T> void read(T &x)
{
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T>void write(T x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x>9)
    {
        write(x/10);
    }
    putchar(x%10+'0');
}
ll T,x,n,t;
bool flag;
int main()
{
    read(T);
    while(T--)
    {
        t=0;
        read(n);
        cin>>x;
        t=x%2;
        flag=false;
        for(int i=1;i<n;i++)
        {
            read(x);
            if(x%2!=t)
            {
                flag=true;
            }
        }
        if(flag&&n!=1)
        {
            puts("NO");
        }
        else
        {
            puts("YES");
        }
    }
    return 0;
}

B. Yet Another Palindrome Problem

题意

给你一个字符串,问他的子串(不一定连续)有没有至少一个长度不少于3的回文串

用一个数组记录数a[i]出现的第一个位置,然后如果再遇到它并且两者之间至少有一个数,就可以构成

代码

#include<bits/stdc++.h>
#define mem(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int inf=0x7f7f7f7f;
const int maxn=5000+100;
template<typename T> void read(T &x)
{
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T>void write(T x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x>9)
    {
        write(x/10);
    }
    putchar(x%10+'0');
}
ll T,n,x,vis[maxn];
bool flag;
int main()
{
    read(T);
    while(T--)
    {
        flag=true;
        memset(vis,-1,sizeof(vis));
        read(n);
        for(int i=0;i<n;i++)
        {
            read(x);
            if(!flag)
            {
                continue;
            }
            if(vis[x]>=0&&i-vis[x]>1)
            {
                puts("YES");
                flag=false;
            }
            else if(vis[x]<0)
            {
                vis[x]=i;
            }
        }
        if(flag)
        {
            puts("NO");
        }
    }
    return 0;
}

C. Frog Jumps

题意

有一只小青蛙,他开始时在0号位置,他要到n+1号位置去,中间1-n位置用一个字符串描述他的行动规则。如果s[i]是L,则他必须向左走,且在不超出范围的情况下至少走一步,它也可以走d步,同理R则是向右走。问在这只小青蛙能够到达n+1号位置的情况下,d的最小值是多少

这个很像二分答案,然而二分答案不好做,可能会TLE,正解应该是寻找最近的R值之间的距离。可以这样理解,如果小青蛙跳在了L上,他想走出去总要跳到一个R上面去,如果用贪心的思想,那就让他每次都是走在R上面。而这种情况下,最小的d应该就是两个R之间的最小距离。这里将n+1号位置标为R,可以更好处理n+1号点,读者可以自己动手试试。

代码

#include<bits/stdc++.h>
#define mem(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int inf=0x7f7f7f7f;
const int maxn=2e5+10;
template<typename T> void read(T &x)
{
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T>void write(T x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x>9)
    {
        write(x/10);
    }
    putchar(x%10+'0');
}
ll T;
ll ans,n,before;
char s[maxn];
int main()
{
    read(T);
    while(T--)
    {
        before=0;
        ans=0;
        s[0]='L';
        scanf("%s",s+1);
        n=strlen(s);
        s[n]='R';
        for(int i=1;i<=n;i++)
        {
            if(s[i]=='R')
            {
                ans=max(ans,i-before);
                before=i;
            }
        }
        write(ans);
        putchar('\n');
    }
    return 0;
}

D. Pair of Topics

题意

给出两个数组a和b,求满足a[i]+a[j]>b[i]+b[j]的(i,j)对有多少个。其中(i,j),(j,i)算一对。

比较操蛋的题,开始还以为这里的i和j是有先后顺序的,后来才发现他们是无序的。计算c[i]=a[i]-b[i],然后对c[i]进行排序,如果满足上述条件的话,应该有c[i]+c[j]=a[i]-b[i]+a[j]-b[j]>0。用两个指针l和r计算配对数即可。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T> void read(T &x)
{
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T>void write(T x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x>9)
    {
        write(x/10);
    }
    putchar(x%10+'0');
}
const ll maxn=2e5+10;
ll n,a[maxn],b[maxn],c[maxn],l,r,ans;
int main()
{
    read(n);
    for(int i=1;i<=n;i++)
    {
        read(a[i]);
    }
    for(int i=1;i<=n;i++)
    {
        read(b[i]);
    }
    for(int i=1;i<=n;i++)
    {
        c[i]=a[i]-b[i];
    }
    sort(c+1,c+1+n);
    l=1,r=n,ans=0;
    while(l!=r)
    {
        if(c[l]+c[r]>0)
        {
            ans+=r-l;
            r--;
        }
        else
        {
            l++;
        }
    }
    write(ans);
    return 0;
}

E. Sleeping Schedule

题意

Vova有一个奇怪的睡眠习惯,Vova会睡上刚好N次。第i次他会在他上一次醒来的a[i]个小时后睡觉。你可以假设Vova是在开头醒来的(初始时间是第0小时)。每次Vova刚好睡一天(换言之,h小时,这个h小时不是平时的24小时,题中会给出)。当他的第i次睡眠在l点和r点之间进行时被称之为好睡眠。它可以控制自己在第i次睡眠预定的a[i]小时后睡觉,也可以是在a[i]-1小时后。求这n次睡眠他的好睡眠最多可以有多少次

去看看题目后面的note能更好理解题意。本题用DP,状态转移方程在代码里。

代码

#include<bits/stdc++.h>
#define mem(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int inf=0x7f7f7f7f;
const int maxn=2000+200;
template<typename T> void read(T &x)
{
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T>void write(T x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x>9)
    {
        write(x/10);
    }
    putchar(x%10+'0');
}
ll n,h,l,r,x,ans=0;
ll sum[maxn],dp[maxn][maxn];
void init()
{
    mem(sum);
    mem(dp);
    read(n);
    read(h);
    read(l);
    read(r);
    for(int i=1;i<=n;i++)
    {
        read(x);
        sum[i]=x+sum[i-1];
    }
    return;
}
void work()
{
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=i;j++)
        {
            dp[i][j]=max(dp[i-1][j],j ? dp[i-1][j-1]:0)+bool((sum[i]-j)%h>=l&&(sum[i]-j)%h<=r);
        }
    }
    for(int i=0;i<=n;i++)
    {
        ans=max(ans,dp[n][i]);
    }
    write(ans);
    return;
}
int main()
{
    init();
    work();
    return 0;
}

F. Maximum White Subtree

给定一棵树,每个节点还有额外的属性颜色。每个数的W值等于白点数-黑点数,求包含i节点的树的最大 w值

比赛的时候没看到这题,看到大佬们的代码时还以为又是link-cut-tree等我不知道的玄学算法,后面仔细看了看并不是。树形DP,第一次dfs尽量的找到附近的能使子树W值最大的节点(但访问不到转过来的father父节点),后面的dfs2便是处理father那边的节点,尽量弄大

代码

#include<bits/stdc++.h>
#define mem(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int inf=0x7f7f7f7f;
const int maxn=2e5+10;
vector<int> e[maxn];
int ans[maxn],a[maxn];
int n,u,v;
template<typename T> void read(T &x)
{
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T>void write(T x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x>9)
    {
        write(x/10);
    }
    putchar(x%10+'0');
}
int dfs(int u,int fa)
{
    ans[u]=a[u] ? 1:-1;
    for(int i=0;i<e[u].size();i++)
    {
        int v=e[u][i];
        if(v!=fa)
        {
            ans[u]+=max(0,dfs(v,u));
        }
    }
    return max(0,ans[u]);
}
void dfs2(int u,int fa)
{
    if(ans[u]==-1)
    {
        ans[u]+=max(0,ans[fa]);
    }
    else
    {
        ans[u]=max(ans[u],ans[fa]);
    }
    for(int i=0;i<e[u].size();i++)
    {
        int v=e[u][i];
        if(v!=fa)
        {
            dfs2(v,u);
        }
    }
    return;
}
int main()
{
    read(n);
    for(int i=1;i<=n;i++)
    {
        read(a[i]);
    }
    for(int i=1;i<n;i++)
    {
        read(u);
        read(v);
        e[u].push_back(v);
        e[v].push_back(u);
    }
    dfs(1,1);
    dfs2(1,0);
    for(int i=1;i<=n;i++)
    {
        write(ans[i]);
        putchar(' ');
    }
    return 0;
}
发布了10 篇原创文章 · 获赞 2 · 访问量 2419

猜你喜欢

转载自blog.csdn.net/STL_CC/article/details/104831234