Codeforces 1368F - Lamps on a Circle (交互博弈)
这题也太新颖了吧.. 交互博弈 以前一直以为交互只能出二分
题意:长度为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 <iostream> #include <stdio.h> #include <algorithm> #include <cmath> #include <vector> #include <map> #include <string.h> #include <string> using namespace std; int vis[1005]; int now[1005]; vector<int> g; 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; }