这题也太新颖了吧.. 交互博弈 以前一直以为交互只能出二分
题意:长度为n的环形灯 玩家有两种操作 结束游戏 或者选择k个灯点亮 每次这个k是玩家自己选的
玩家操作后让电脑操作 电脑选择一个最优的点x 然后关掉从x开始的连续k个灯
玩家想要点亮更多的灯 电脑则相反
让你来操作 如果达到了理论上最多灯的状态就算ac了
题解:模拟一下操作就找到规律了..
如果玩家上一次操作点亮了k个灯 如果当前连续亮灯的最长序列为x <= k
那么电脑操作了之后 至少会多点亮一个灯 就这样一直贪心下去..
所以我们一开始枚举 最长的连续亮灯长度
举个例子枚举的最长是2 就类似110110110.. 的把每个灯标记 1就标记为最后要点亮的灯
再比如n=11的时候 枚举的最长=2 11011011010 注意n和1相邻一定为0
然后模拟一下就发现这种情况 能最多点亮5个 = (n/3)*(2) + (n%3-1) - 2
k = 7 11011011010 -> 00000001010
k = 5 11011011010 -> 00000011010
k = 4 11011011010 -> 00001011010
k = 3 11011011010 -> 00011011010
之后无论如何也不能点亮更多灯了
然后枚举每一个长度 选一个最优的
#include
#include
#include
#include
#include
#include
int vis[1005];
int now[1005];
vector
int main() {
int n;
cin>>n;
int ans = 0;
int fz = 2;
for(int i = 2; i <= n / 2; i++) {
int res = (n / i) \* (i - 1);
if(n % i != 0) res += n % i - 1;
res -= (i - 1);
if(res > ans) ans = res, fz = i;
}
//cout << ans << endl;
for(int i = 1; i <= n; i++) if(i % fz) vis\[i\] = 1;
vis\[n\] = 0;
int lask = 0;
int x = 0;
while(1) {
if(x == -1) break;
int rr = 0;
int pos = x;
while(lask--) {
now\[pos\] = 0;
pos++;
if(pos > n) pos = 1;
}
for(int i = 1; i <= n; i++) if(now\[i\]) rr++;
if(rr >= ans) {
puts("0");
cout.flush();
break;
}
g.clear();
for(int i = 1; i <= n; i++) {
if(!now\[i\] && vis\[i\]) {
now\[i\] = 1;
g.push\_back(i);
}
}
lask = g.size();
printf("%d", lask);
for(int i = 0; i < lask; i++) printf(" %d", g\[i\]); puts("");
cout.flush();
cin>>x;
}
return 0;
}
手机扫一扫
移动阅读更方便
你可能感兴趣的文章