Codeforces Round #573 (Div. 2) E. Tokitsukaze and Duel (博弈)

time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
"Duel!"

Betting on the lovely princess Claris, the duel between Tokitsukaze and Quailty has started.

There are n cards in a row. Each card has two sides, one of which has color. At first, some of these cards are with color sides facing up and others are with color sides facing down. Then they take turns flipping cards, in which Tokitsukaze moves first. In each move, one should choose exactly k consecutive cards and flip them to the same side, which means to make their color sides all face up or all face down. If all the color sides of these n cards face the same direction after one‘s move, the one who takes this move will win.

Princess Claris wants to know who will win the game if Tokitsukaze and Quailty are so clever that they won‘t make mistakes.

Input
The first line contains two integers n and k (1≤k≤n≤105).

The second line contains a single string of length n that only consists of 0 and 1, representing the situation of these n cards, where the color side of the i-th card faces up if the i-th character is 1, or otherwise, it faces down and the i-th character is 0.

Output
Print "once again" (without quotes) if the total number of their moves can exceed 109, which is considered a draw.

In other cases, print "tokitsukaze" (without quotes) if Tokitsukaze will win, or "quailty" (without quotes) if Quailty will win.

Note that the output characters are case-sensitive, and any wrong spelling would be rejected.

Examples
inputCopy
4 2
0101
outputCopy
quailty
inputCopy
6 1
010101
outputCopy
once again
inputCopy
6 5
010101
outputCopy
tokitsukaze
inputCopy
4 1
0011
outputCopy
once again
Note
In the first example, no matter how Tokitsukaze moves, there would be three cards with color sides facing the same direction after her move, and Quailty can flip the last card to this direction and win.

In the second example, no matter how Tokitsukaze moves, Quailty can choose the same card and flip back to the initial situation, which can allow the game to end in a draw.

In the third example, Tokitsukaze can win by flipping the leftmost five cards up or flipping the rightmost five cards down.

The fourth example can be explained in the same way as the second example does.

题意:
给你一个长度为n的01字符串,和一个整数k。二人进行做博弈游戏,每个人必须选择一个连续的k个字符,把这连续的k个字符全变为0或者1

如果某次操作之后整个字符串全为1或者0,那么这个胜利,如果有无限多步要走,那么算平局,假设二人都绝顶聪明。给你初始局面,问游戏结果是什么?

思路:

首先应该明确,如果先手要赢,他一定要在第一步就赢,否则就不能再赢了。

后手要赢的话,他要在他走的第一步赢,不然也不能再赢了、因为另外一个人可以重复选择他刚刚选择的区间,使其不停的翻转,可以知道这样是一直循环下去而且无意义的。

为什么要这样呢?因为一个人如果不能赢,那么平局就是最优的决策,所以不能赢的人,会用这个方法使其平局。

然后来看什么情况下先手会一步赢?

选择一个连续的k个字符区间后,这个区间以外的字符全为1或者全为0,先手使其区间变为对应的字符就可以赢得。

我们可以通过前缀和 以及 枚举区间 进行判定先手是否能赢 ,时间复杂度是 O(n )

如果先手不能赢,接下来看后手能否一步赢?

能赢的条件如下:

1、2*k>=n

不然个人操作后无法覆盖整个字符串,先手不会让你赢的。

2、 k!=1
先手如果第一次操作没法赢,那就把字符保持原来的样子,把状态给你,你同样没法赢。

3、 因为2*k>=n 所以先手操作过之后,一定会有一个至少连续k个字符的区间是相同的。

    那么先手肯定不会从选首尾的,因为这样直接就送后手赢了。

    那么先手肯定会选择中间的k个连续字符,那么我们就枚举中间k个连续字符区间的左右的剩余区间(例如左边的是a区间,右边的是b区间。)

    我们判的是否a区间为都为0或者1,以及b。  因为先手决定聪明,所以他会尽量不让后手赢,所以就要枚举区间,判定没有一个情况下a和b不是合法的。

    以及:

     int len=n-k-1;

           if(a[len]==a[len+1]||a[n-len]==a[n-len+1]||a[1]==a[n])

                    后手也不可能赢。

先手后手都不能一步赢的话,
结果就一定是平局了。

细节见代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#define ALL(x) (x).begin(), (x).end()
#define rt return
#define dll(x) scanf("%I64d",&x)
#define xll(x) printf("%I64d\n",x)
#define sz(a) int(a.size())
#define all(a) a.begin(), a.end()
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define gg(x) getInt(&x)
#define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
ll powmod(ll a,ll b,ll MOD){ll ans=1;while(b){if(b%2)ans=ans*a%MOD;a=a*a%MOD;b/=2;}return ans;}
inline void getInt(int* p);
const int maxn=1000010;
const int inf=0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
char s[maxn];
int a[maxn];
int n,k;
bool check_sec()
{
    if(k*2<n||k==1)return false;
    int len=n-k-1;
    for(int i=2;i<=len;++i)
    {
        if(a[i-1]!=a[i-2]||a[n-i]!=a[n-i+1])return false;
    }
    if(a[len-1]==a[len]||a[n-len-1]==a[n-len]||a[0]==a[n-1])return false;
    return true;
}
int main()
{
    //freopen("D:\\common_text\\code_stream\\in.txt","r",stdin);
    //freopen("D:\\common_text\code_stream\\out.txt","w",stdout);

    gbtb;
    cin>>n>>k;
    cin>>s;
    if(k>=n-1)
    {
        cout<<"tokitsukaze"<<endl;
    }else
    {
        for(int i=0;i<n;++i)
        {
            a[i]=s[i]-'0';
        }
        for(int i=1;i<n;i++)
        {
            a[i]+=a[i-1];
        }
        int isok=0;
        for(int i=k-1;i<n;i++)
        {
            if(a[n-1]-a[i]==0&&((i-k>=0&&a[i-k]==0)||(i-k<0)))
            {
                isok=1;
                break;
            }else if(a[n-1]-a[i]==n-1-i&&((i-k>=0&&a[i-k]==i-k+1)||(i-k<0)))
            {
                isok=1;
                break;
            }
        }
        if(isok)
        {
            cout<<"tokitsukaze"<<endl;
        }else
        {
            for(int i=0;i<n;++i)
            {
                a[i]=s[i]-'0';
            }
            if(check_sec())
            {
                cout<<"quailty"<<endl;
            }else
            {
                cout<<"once again"<<endl;
            }
        }
    }

    return 0;
}

inline void getInt(int* p) {
    char ch;
    do {
        ch = getchar();
    } while (ch == ' ' || ch == '\n');
    if (ch == '-') {
        *p = -(getchar() - '0');
        while ((ch = getchar()) >= '0' && ch <= '9') {
            *p = *p * 10 - ch + '0';
        }
    }
    else {
        *p = ch - '0';
        while ((ch = getchar()) >= '0' && ch <= '9') {
            *p = *p * 10 + ch - '0';
        }
    }
}

原文地址:https://www.cnblogs.com/qieqiemin/p/11181357.html

时间: 2024-11-09 03:36:07

Codeforces Round #573 (Div. 2) E. Tokitsukaze and Duel (博弈)的相关文章

Codeforces Round #573 (Div. 2) A. Tokitsukaze and Enhancement

Codeforces Round #573 (Div. 2) A. Tokitsukaze and Enhancement Tokitsukaze is one of the characters in the game "Kantai Collection". In this game, every character has a common attribute — health points, shortened to HP. In general, different valu

Codeforces Round #573 (Div. 2).A

A - Tokitsukaze and Enhancement 题目链接:http://codeforces.com/contest/1191/problem/A 题目: Tokitsukaze is one of the characters in the game "Kantai Collection". In this game, every character has a common attribute — health points, shortened to HP. In

Codeforces Round #573 (Div. 2)

D. Tokitsukaze, CSL and Stone Game 题意:有n堆石头,每人每次只能去一颗石子,若轮到当前人没任何一堆石子可以取或当前人取到后剩下有俩堆石子个数相同则当前人输: 给定石子序列. 分析:1.若有类似“2 3 3 ”则后手胜,因为有这个序列就必须在这个序列中去石子(因为如果在这个序列以外取子,则会导致输的后者情况),但在这个序列中取不到可解情况,所以该状态为必败态: 2.若序列中有俩对相同的石子,则后手胜: 3.除1.2情况外就把利用sum+起来,每个加就+a[i]-

Codeforces Round #573 (Div. 2) A B C

ATokitsukaze and Enhancement #include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e5+100; int x; int main(){ cin >> x; int cnt = 0; if( x%4 <= 1 || x%4==3){ if (x%4==0) cnt=1; if(x%4 ==3) cnt=2; cout << cnt

Codeforces Round #281 (Div. 2) D. Vasya and Chess 博弈

D. Vasya and Chess Vasya decided to learn to play chess. Classic chess doesn't seem interesting to him, so he plays his own sort of chess. The queen is the piece that captures all squares on its vertical, horizontal and diagonal lines. If the cell is

Codeforces Round #428 (Div. 2)

Codeforces Round #428 (Div. 2) A    看懂题目意思就知道做了 #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a; i<=b; ++i) #define per(i,b,a) for (int i=b; i>=a; --i

Codeforces Round #424 (Div. 2) D. Office Keys(dp)

题目链接:Codeforces Round #424 (Div. 2) D. Office Keys 题意: 在一条轴上有n个人,和m个钥匙,门在s位置. 现在每个人走单位距离需要单位时间. 每个钥匙只能被一个人拿. 求全部的人拿到钥匙并且走到门的最短时间. 题解: 显然没有交叉的情况,因为如果交叉的话可能不是最优解. 然后考虑dp[i][j]表示第i个人拿了第j把钥匙,然后 dp[i][j]=max(val(i,j),min(dp[i-1][i-1~j]))   val(i,j)表示第i个人拿

Codeforces Round #424 (Div. 2) C. Jury Marks(乱搞)

题目链接:Codeforces Round #424 (Div. 2) C. Jury Marks 题意: 给你一个有n个数序列,现在让你确定一个x,使得x通过挨着加这个序列的每一个数能出现所有给出的k个数. 问合法的x有多少个.题目保证这k个数完全不同. 题解: 显然,要将这n个数求一下前缀和,并且排一下序,这样,能出现的数就可以表示为x+a,x+b,x+c了. 这里 x+a,x+b,x+c是递增的.这里我把这个序列叫做A序列 然后对于给出的k个数,我们也排一下序,这里我把它叫做B序列,如果我

[Codeforces] Round #352 (Div. 2)

人生不止眼前的狗血,还有远方的狗带 A题B题一如既往的丝帛题 A题题意:询问按照12345678910111213...的顺序排列下去第n(n<=10^3)个数是多少 题解:打表,输出 1 #include<bits/stdc++.h> 2 using namespace std; 3 int dig[10],A[1005]; 4 int main(){ 5 int aa=0; 6 for(int i=1;;i++){ 7 int x=i,dd=0; 8 while(x)dig[++dd