题目大意:
有26堆石子,你可以选其中的若干堆取走每个选定堆中的一颗石子,没法取的人失败。你需要选择先手和后手,然后与程序交互,给出必胜的方案。
做法:
- 我们先看只有一堆的情况,如果这一堆中的石子数为偶数,那么先手必败,反之如果是奇数,那么先手必胜;
- 我们可以推广到26堆的情况,如果不存在奇数堆的石子那么先手必败,否则先手必胜。
- 至此,我们得到了一个最优方案。如果不存在奇数堆的石子那么我们选则后手,否则选先手。
- 每次将奇数堆的石子取走,使得对方面临必败状态即可。
代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <set>
using namespace std;
char str[1000];
set<int>s[26];
int hand=2,oper[1000],os,ct;
bool get()
{
int p;
scanf("%d",&os);
if(os==-1)return true;
while(os--)
{
scanf("%d",&p);
s[str[p-1]-'a'].erase(p);
}
return false;
}
int main()
{
scanf("%s",str);
int len=strlen(str);
for(int i=0;i<len;i++)s[str[i]-'a'].insert(i+1);
for(int i=0;i<26;i++)
if(s[i].size()%2){hand=1;break;} //存在奇数堆选先手
printf("%d\n",hand);
fflush(stdout);
if(hand==2)get();
while(1){
int ct=0;
for(int i=0;i<26;i++)
if(s[i].size()%2)
{
oper[ct++]=*s[i].begin();
s[i].erase(s[i].begin());
//拿掉奇数堆
}
printf("%d",ct);
for(int i=0;i<ct;i++)printf(" %d",oper[i]);
printf("\n");
fflush(stdout);
if(get())break;
}
return 0;
}