CF1418C Mortal Kombat Tower(找规律)

您和您的朋友正在玩游戏真人快打XI。您正在尝试通过挑战塔。该塔中有n个凸台,从1到n。第i个老板的类型是ai。如果第i个首领很容易,则其类型为ai = 0,否则,此首领为坚硬且其类型为ai = 1。

题意:

在一个会话中,您或您的朋友可以杀死一个或两个老板(您和您的朋友都不能跳过该会话,因此在一个会话中被杀死的老板最少要有一个)。在您的朋友会话之后,您的会话开始,然后再次您的朋友会话开始,您的会话开始,依此类推。第一场是您朋友的一场。

您的朋友需要变得良好,因为他实际上无法杀死艰难的老板。为了杀死他们,他使用了跳过点。一个跳过点可以用来杀死一个坚强的上司。

您的任务是找到您的朋友需要使用的最小跳过点数,以便您和您的朋友按给定顺序杀死所有n个头目。

例如:假设n = 8,a = [1,0,1,1,0,1,1,1]。那么最好的做法是:

您的朋友杀死了两个首领,对首个老板使用一个跳跃点;
您杀死了第三和第四位老板;
您的朋友杀死了第五任老板;
你杀死了第六和第七个boss;
您的朋友使用一个跳过点杀死了最后一个老板,因此使用两个跳过点完成了塔。
您必须回答t个独立的测试用例。

输入项
输入的第一行包含一个整数t(1≤t≤2⋅104)—测试用例的数量。然后是t个测试用例。

测试用例的第一行包含一个整数n(1≤n≤2⋅105)-凸台数。测试用例的第二行包含n个整数a1,a2,…,an(0≤ai≤1),其中ai是第i个首部的类型。

保证n的总和不超过2⋅105(∑n≤2⋅105)。

输出量
对于每个测试用例,请打印答案:朋友需要使用的最小跳过点数,以便您和朋友按给定顺序杀死所有n个头目。

题解:

规律题,思考后可以发现,除了开头为1的情况,任意一段连续为1的子序列,都能转化为我先手,朋友后手的情况。依次枚举算贡献即可。

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+100;
const int inf=1e9;
int n;
int t;
int a[maxn];
int main () {
    scanf("%d",&t);
    while (t--) {
        scanf("%d",&n);
        for (int i=1;i<=n;i++) scanf("%d",a+i);
        a[n+1]=0;
        int ans=0;
        int tot=0;
        //贪心
        //把尽可能多的1留给我
        //对于一段连续是1的长度是k的区间
        //如果朋友先手, ans+=k/3+(k%3>0?1:0)
        //如果我先手,ans+=k/3
        int f=0;
        for (int i=1;i<=n;i++) {
            if (!a[i]) continue;
            int j;
            for (j=i;j<=n;j++) if (a[j]==0) break;
            int k=j-i;
            if (i>1) 
                ans+=k/3;
            else {
                ans+=k/3+(k%3>0?1:0);
                f++; 
            }
            i=j-1;
        }
        printf("%d\n",ans);
    }
}

 

posted @ 2020-09-15 15:14  zlc0405  阅读(573)  评论(0编辑  收藏  举报