Codeforces Round #814 (Div. 2)

目录

A. Chip Game(博弈)

B. Mathematical Circus

C. Fighting Tournament

D1.D2. Burenka and Traditions


A. Chip Game(博弈)

题意:给你了n*m的格子,Tonya和Burenka从左下角出发,两人只能走奇数长度的路.假设两人足够聪明我们如何能够,不能走了的就失败(只能往右或者往上走).

思路:已知我们直接把从左往右和从下往上两条路进行分割,当这两条路为奇数长度可以把它们分成1,否则分成2(因为写一个人改变上一个人的奇偶性,所以奇数相当于上一个人走一步,偶数为两个人都走一步).

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N =5e5+10,mod=998244353;
void solve()
{
    int n,m;
    cin>>n>>m;
    if(n%2==m%2)
        cout<<"Tonya"<<endl;
    else
        cout<<"Burenka"<<endl;
    return ;
}
signed main()
{
    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);
    int t;
    cin>>t;
    while(t--)
       solve();
    return 0;
}

B. Mathematical Circus

题意:我们有一个偶数长度n的数组,还有一个k,我们要把数组分成n/2对.每对为(a,b),并且满足(a+k)*b被4整除.问是否可以构造出.

思路:

1.当k为奇数时,已知奇数+奇数=偶数.偶数拥有因子2,两个偶数相乘至少有2个因子2,肯定能被4整除,所以这种情况就之就输出(奇数,偶数)搭配即可.

2.当k为偶数时,我们发现如果含有一个偶数%4=0那么这一组就确定了,(奇数,4的倍数).那么还剩下2的倍数和其他奇数,显然奇数+偶数还是奇数,所以我们要在2的倍数上下功夫.当k不是2的倍数的情况下,(k+2的倍数)肯定是4的倍数.如果k是4的倍数就无法成立.

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N =2e5+10,mod=998244353;
int a[N],b[N];
void solve()
{
    int n,k;
    cin>>n>>k;
    if(k%2)
    {
        int f=0;
        for(int i=1;i<=n/2;i++)
        {
            a[i]=i*2-1;
            b[i]=i*2;
        }
        for(int i=1;i<=n/2;i++)
        {
            if((a[i]+k)*b[i]%4)
            {
                f=1;
                break;
            }
        }
        if(f)
            cout<<"NO"<<endl;
        else
        {
            cout<<"YES"<<endl;
            for(int i=1;i<=n/2;i++)
                cout<<a[i]<<" "<<b[i]<<endl;
        }
    }
    else
    {
        int f=0;
        if(k%4)
        {
            for(int i=1;i<=n/2;i++)
            {
                if((i*2)%4)
                {
                    a[i]=i*2;
                    b[i]=i*2-1;
                }
                else
                {
                    a[i]=i*2-1;
                    b[i]=i*2;
                }
            }
            for(int i=1;i<=n/2;i++)
            {
                if((a[i]+k)*b[i]%4)
                {
                    f=1;
                    break;
                }
            }
            if(f)
                cout<<"NO"<<endl;
            else
            {
                cout<<"YES"<<endl;
                for(int i=1;i<=n/2;i++)
                    cout<<a[i]<<" "<<b[i]<<endl;
            }
        }
        else
            cout<<"NO"<<endl;
    }
    return ;
}
signed main()
{
    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);
    int t;
    cin>>t;
    while(t--)
       solve();
    return 0;
}

C. Fighting Tournament

问题:有n个运动员,q次询问,每次询问包含两个数i,k.意为询问第i位运动员在进行k场比赛的时候会胜利多少场.(比赛规则是取队列前两个队员比赛,胜利者放回队伍前端,失败者在队伍后端)

思路:我们知道,有一个武力值最高的运动员,如果他开始了比赛,俺么后面无论如何比赛他都会一直在队伍的首位并且一直胜利.所以我们先跑一遍循环,对于每个运动员第一次和最后一次胜利进行处理得出来.然后分情况讨论:

1.当当前运动员在最强运动员后面,或者比赛根本比不到他,或者他第一次胜利的场次>k,或者根本没有胜利过的话,这个询问就是直接输出0.

2.当询问的人就是最强运动员时,直接输出k+1-他第一次胜利的场次

3.生育情况直接输出min(k,f[i].second)-f[i].first+1,也就是最后一次胜利和第一次胜利的场次之间共赢了多少场即可.

#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int,int> PII;
const int N =1e5+10,mod=998244353;
int a[N];
void solve()
{
    int n,q,maxid=1;
    cin>>n>>q;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        if(a[i]>a[maxid])
            maxid=i;
    }
    vector<PII>f(n+1);
    int sheng=a[1];
    int pos=1;
    for(int i=2;i<=n;i++)
    {
        if(a[i]<sheng)
        {
            if(f[pos].second==0)
                f[pos].first=i-1;
            f[pos].second=i-1;
        }
        else if(a[i]>sheng)
        {
            sheng=a[i];
            pos=i;
            f[pos].first=i-1;
			f[pos].second=i-1;
        }
    }
    int i,k;
    while(q--)
    {
        cin>>i>>k;
        if(i>maxid||k<i-1||f[i].first>k||f[i].first==0)
            cout<<"0"<<endl;
        else if(i==maxid)
            cout<<k+1-f[i].first<<endl;
        else
            cout<<min(k,f[i].second)-f[i].first+1<<endl;
    }
}
signed main()
{
    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);
    int t;
    cin>>t;
    while(t--)
       solve();
    return 0;
}

D1.D2. Burenka and Traditions

问题:有一个长为n的数组,我们每次可以选择一个l,r和任意一个x然后花费(l-r+1)/2(向上取整)的能量去让[l,r]之间的数组元素都异或上x,问最少花费多少能量可以把整个数组所有元素化为0.

思路:我们可以贪心的去变化,花费一点能量把遍历位置前一位的数移动到下一位去,例如[1,2,4]变化之后就是[0,3,4]->[0,0,7],用一个f数组记录此时的花费为多少,用一个map记录一下移动之后a[i]的位置在哪里.如果我在进行a[i]的变化之后,a[i]在之前出现过(map判断)那么这一个区间异或和就为0,那么我们直接进行f的状态转移f[i]=max(f[i],f[map[a[i]]]+区间长度).当他为0我们就可以直接往下进行操作而不是把这一位转移到下一位了.

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N =5e5+10,mod=998244353;
int a[N];
int f[N];
void solve()
{
    map<int,int>ma;
    int n;
    cin>>n;
    ma[0]=0;
    f[0]=0;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    for(int i=1;i<=n;i++)
    {
        a[i]^=a[i-1];
        f[i]=f[i-1]+1;
        if(ma.count(a[i]))
        {
            f[i]=min(f[i],f[ma[a[i]]]+i-ma[a[i]]-1);
        }
        ma[a[i]]=i;
    }
    cout<<f[n]<<endl;
    return ;
}
signed main()
{
    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);
    int t;
    cin>>t;
    while(t--)
       solve();
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值