zoukankan      html  css  js  c++  java
  • E

    "Duel!"

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

    There are nn 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 kk 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 nn 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 nn and kk (1kn1051≤k≤n≤105).

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

    Output

    Print "once again" (without quotes) if the total number of their moves can exceed 109109, 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

    Input
    4 2
    0101
    
    Output
    quailty
    
    Input
    6 1
    010101
    
    Output
    once again
    
    Input
    6 5
    010101
    
    Output
    tokitsukaze
    
    Input
    4 1
    0011
    
    Output
    once again

    解题思路:先手和后手要么一出手就赢,要么就会平局,因为两个人都聪明绝顶(暗示脱发),都想赢,如果一出手赢不了,然后两个人就可以重复同一步操作,抵消对方带来的不好影响,因此导致平局
    先手必赢条件:1.不用翻转就可以赢
           2.翻转长度 k >= n ,那么只要翻转一次就可以赢
           3.k < n ,但是只要一次翻转就可以赢
    后手赢的条件:那就是先手第一次无论怎么翻转都不能赢,但是到了后手无论何种情况下都能赢
            1.k!=1。因为如果先手赢不了,那他就相当于不动序列,留给后手,后手也赢不了
            2.2*k>=n,因为后手一出手必须赢,不然先手就可以抵消后手对于序列的影响而导致平局。
            3.2*k>=n的时候,那必定会存在一个区间k内的字符一定是相同的,考虑到先手(聪明绝顶,肯定不希望后手赢),那么我们只要让先手无论如何都会输就好了
            首尾肯定是不会选的,毕竟先手聪明绝顶。
            那么先手肯定会选择中间的k个连续字符,那么我们就枚举中间k个连续字符区间的左右的剩余区间(例如左边的是a区间,右边的是b区间。)我们判的是否a区间为都为0或者1,以及b。 因为先手决定聪明,所以他会尽量不让后手赢,所以就要枚举区间,判定没有一个情况下a和b不是合法的。
            并且区间a和区间b也必须是不同的
    注意:判断后手赢得条件时,如果暴力判断(n2)会超时,因此用到里“窗体移动”的方法(这个是我在网上看到的,应该是这个叫法),区间k不断向右移动,同时保证左区间a和右区间b也满足条件
      要满足条件的话,去加入区间的元素,只要和它的上一位元素(或是下一位元素)比较就可以知道时候满足条件,这样的复杂度就降到了O(n),还有就是注意边界情况的处理。就是左区间或者右区间有且仅有1一个元素的时候,这个时候区间中没有东西可以进行比较,要满足的是区间a和区间b也必须是不同的。
     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
     4 typedef long long ll;
     5 const int P = 998244353;
     6 const int inf = 0x3f3f3f3f;
     7 const int maxn = 500030;
     8 vector<int>one,zero;
     9 int n,k;
    10 int str[maxn];
    11 char s;
    12 int check1(){
    13     if(one.size() == 0 || zero.size() == 0 || k >= n){
    14         return 1;
    15     }
    16     int lz = -1,rz = -1,lo = -1,ro = -1;
    17     for(int i = 1; i <= n ; i++){
    18         if(lz == -1 && str[i] == 0){
    19             lz = i;
    20         }
    21         if(lo == -1 && str[i] == 1){
    22             lo = i;
    23         }
    24         if(lz != -1 && lo != -1) break;
    25     }
    26     for(int i = n ; i >= 1; i--){
    27         if(rz == -1 && str[i] == 0){
    28             rz = i;
    29         }
    30         if(ro == -1 && str[i] == 1){
    31             ro = i;
    32         }
    33         if(rz != -1 && ro != -1) break;
    34     }
    35     if(k >= min(ro - lo + 1,rz - lz + 1)) return 1;
    36     return 0;
    37 }
    38 int check2(){
    39     if(k == 1) return 0;
    40     if(2 * k < n) return 0;
    41     int len = n - k;
    42     for(int i = 3 ; i < len ; i++){
    43         if(str[i - 1] != str[i - 2] || str[i + k] != str[i + k + 1]) return 0;
    44     }
    45     if(str[1] == str[n] || str[1] == str[k+2] || str[n] == str[n - k - 1]) return 0;
    46     return 1;
    47 }
    48 
    49 
    50 
    51 int main(){
    52     gbtb;
    53     cin>>n>>k;
    54     for(int i = 1; i <= n ; i++){
    55         cin>>s; str[i] = s-'0';
    56         if(str[i] == 1) one.push_back(i);
    57         else zero.push_back(i);
    58     }
    59     if(check1()){
    60         cout<<"tokitsukaze"<<endl;
    61     }else if(check2()){
    62         cout<<"quailty"<<endl;
    63     }else{
    64         cout<<"once again"<<endl;
    65     }
    66     return 0;
    67 }
    View Code

    一个从很久以前就开始做的梦。

  • 相关阅读:
    windows 临界区 InitializeCriticalSectionAndSpinCount以及InitializeCriticalSection的区别
    SRWLock 轻量级的读写锁
    QT 遍历获取Form上的控件
    mssql 查询作业执行情况,耗时 等
    C++ builder FMX 遍历窗口所有控件 并 动态消失
    delphi fmx 控件从天上掉下来
    Vue2入门必知必会
    人人开源&项目脚手架&微服务整合
    Spring Security应用到源码分析
    K8S系统学习笔记总览
  • 原文地址:https://www.cnblogs.com/DreamACMer/p/11182788.html
Copyright © 2011-2022 走看看