Codeforces Round 797 (Div. 3)

目录

A. Print a Pedestal (Codeforces logo?)

B. Array Decrements

C. Restoring the Duration of Tasks

D. Black and White Stripe

E. Price Maximization

F. Shifting String

G. Count the Trains


A. Print a Pedestal (Codeforces logo?)

题意:给你一个数n,要求分成三份,使得大小顺序为2 1 3 ,并要求最大的数,即顺序的第二位最小的数能是几

思路:首先找到n/3的数,根据n%3的余数分类讨论即可

代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

typedef long long ll;
typedef pair pii;

const int N = 1e5 + 10;

int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    
    int t;cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        int c=n/3,d=n%3;
        if(n%3==0)cout<

B. Array Decrements

题意:给定一个数组a和b,每次可以将a的所有数减小1,但是最多只能减到0,判断a数组是否能通过操作与b数组相等。

思路:记录下来每个位置a数组和b数组的差值,如果差值为负数,即a[i]

代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

typedef long long ll;
typedef pair pii;

const int N = 1e5 + 10;

int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    
    int t;cin>>t;
    while(t--)
    {
        int n;cin>>n;
        vectora(n),b(n),c(n),minv(n,0);
        for(auto& x:a)cin>>x;
        for(auto& x:b)cin>>x;

        bool ok=1;
        for(int i=0;itmp)ok=0;
            }
        if(tmp==-1)ok=1;
        
        if(ok)cout<<"YES"<<"\n";
        else cout<<"NO"<<"\n";
    }
    return 0;
}

C. Restoring the Duration of Tasks

题意:给定n个任务的开始时间和结束时间,如果一个任务的结束时间大于下一个任务的开始时间,那么会先把当前任务完成后,再完成下一个任务,问每个任务的实际运行时间

思路:只要判断每个位置的开始时间是否晚于上一任务的结束时间,如果晚于,那么任务实际的运行时间就是该任务的结束时间与开始时间的差值,如果不晚于,那么该任务的实际运行时间就是该任务的结束时间与上一任务结束时间的差值

代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

typedef long long ll;
typedef pair pii;

const int N = 1e5 + 10;

int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    
    int t;cin>>t;
    while(t--)
    {
        int n;cin>>n;
        vectors(n),f(n);

        bool flag=0;
        for(auto& x:s)cin>>x;
        for(auto& x:f)cin>>x;

        cout<=f[i-1])cout<

D. Black and White Stripe

题意:给定一串序列,包含两个字母'B‘和’W',分别代表黑色和白色,再给定一个整数k,问最少将序列中的白色字符修改成黑色字符使得序列中存在连续k个黑色字符

思路:白色的权值为1,黑色为0,求一遍前缀和,然后对于每k段取min即可

代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

typedef long long ll;
typedef pair pii;

const int N = 2e5 + 10;

int s[N];
int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    
    int t;cin>>t;
    while(t--)
    {
        int n,k;cin>>n>>k;
        string str;cin>>str;
        
        for(int i=0;i

E. Price Maximization

题意:给定n(偶数)个货物,和一个整数k,每个货物有一个权值,将货物两两分组,该组的代价为其两个货物的权值和/k,问最大的权值总和

思路:首先每个能整除k的部分一定会统计到答案中,所以我们只需统计%k的余数能凑出多少个k即可,用双指针可以解决

代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

typedef long long ll;
typedef pair pii;

const int N = 1e5 + 10;

int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    
    int t;cin>>t;
    while(t--)
    {
        int n,k;cin>>n>>k;
        vectora(n+1),cnt(k,0);

        ll res=0;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            cnt[a[i]%k]++;
            res+=(a[i]/k);
        }

        int sum=0;
        for(int i=1,j=k-1;i<=j;i++,j--)
        {
            sum+=cnt[j];
            if(i==j)break;
            int t=min(sum,cnt[i]);
            res+=t;
            sum-=t;
        }
        cout<

F. Shifting String

kmp求最小循环节

题意:给定一个字符串个一个排列,每次将字符串按照排列的顺序重新排列,问最少经过多少次后能将字符串回到初始的状态

思路:对于排列,我们可以转换成很多环,每个环是独立开的,对应着一个字符串,求每个字符串的最小循环节,最后对于所有循环节取公倍数即可

对于求字符串的最小循环节可以用kmp求,这题也可以用暴力求

代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

typedef long long ll;
typedef pair pii;

const int N = 1e5 + 10;

int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    
    int t;cin>>t;
    while(t--)
    {
        int n;cin>>n;
        string str;cin>>str;
        str="@"+str;
        vectora(n+1),st(n+1,0);
        for(int i=1;i<=n;i++)cin>>a[i];

        ll ans=1;
        for(int i=1;i<=n;i++)
        {
            string s;
            if(!st[i])
            {
                int u=i;
                while(!st[u])
                {
                    st[u]=1;
                    s+=str[u];
                    u=a[u];
                }

                int len=s.size();
                vectorne(len+1,0);
                s="@"+s;
                
                for(int i=2,j=0;i<=len;i++)
                {
                    while(j&&s[i]!=s[j+1])j=ne[j];
                    if(s[i]==s[j+1])j++;
                    ne[i]=j;
                }

                ll tmp=len-ne[len];
                if(len%tmp)tmp=len;
                ans=ans/__gcd(ans,tmp)*tmp;
            }
        }
        cout<

G. Count the Trains

题意:对于给定的数组a,和q个操作,每次操作将a中的某个位置k减小d,要求数组中每个数的前一个数要大于等于后一个数,如果当前数大于前一个数,那么就会变成前一个数,问,每次操作后数组中有多少个不同的数

思路:可以用map存储数组元素,map的大小就是答案。若位置i的数 x_{i}大于位置i-1的数 x_{i-1} ,就把位置i从map中去除,else,把位置i后 x_{i+j}>x_{i} 的点去除。每次输入k,d,将位置k重新加入map当中执行相同的操作。因为每个数组元素只会减少不会增加,所以那些被删除的元素并不会因为位置k的改变而重新有进入map的可能。

代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

typedef long long ll;
typedef pair pii;

const int N = 1e5 + 10;

int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    
    int t;cin>>t;
    while(t--)
    {
        int n,m;cin>>n>>m;
        vectora(n+1);
        for(int i=1;i<=n;i++)cin>>a[i];

        mapmp;

        auto add = [&](int i,int x)
        {
            mp[i]=x;
            auto it=mp.find(i);

            if(it!=mp.begin()&&x>=prev(it)->second)
            {
                mp.erase(it);
                return;
            }
            while(next(it)!=mp.end()&&x<=next(it)->second)mp.erase(next(it));
        };
        for(int i=1;i<=n;i++)add(i,a[i]);
        
        while(m--)
        {
            int k,d;cin>>k>>d;
            a[k]-=d;
            add(k,a[k]);
            cout<

你可能感兴趣的:(codeforce,算法,c++)