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); } }