Description
有一天YMW看见竞赛室里面放着n个正面向上的杯子,他随手把所有的杯子翻转成正面向下的杯子了。后来突然想起来自己有两只手,于是他尝试同时翻转两只杯子,看下最后能不能翻转成为全部正面朝下。聪明的你看到了这一切,突然脑子里面闪过一个问题,假如每次同时翻转m只杯子,最后能全部翻转成为正面朝下吗?(初始时全部正面朝上)
Input
多组数据,每组数据两个数n和m,以-1,-1结尾
Output
对于每组数据,如果可以输出Yes,不能输出No
Hint
Data Limit:
不少于5组数据,不超过20组数据
对于30%的数据n<=10,m<=5
对于70%的数据n<=100,m<=30
对于100%的数据n<=10000,m<=500
每个输入文件中n和m有一定梯度和差别,保证每个输入中不全为Yes或No
Source
BY BPM
Solution
水题,可耻地因为大小写问题wa了
暴力dfs,观察到翻转的顺序无关,状态只和正面/反面的数量有关,那么搜索+记忆化就可以了
考虑找规律。不难发现若要n个水杯全翻面,则每个杯子需要翻转奇数次。对于偶数n任意m都能满足,对于奇数n只有奇数m能满足。
Code
#include <stdio.h>
#include <string.h>
#define rep(i, st, ed) for (int i = st; i <= ed; i += 1)
#define min(x, y) (x)<(y)?(x):(y)
#define N 12001
int v[N];
bool flag;
inline void dfs(int z, int m, int n){
if (v[z]){return ;}
if (z == 0 || flag){
flag = true;
return ;
}
v[z] = 1;
int lim = min(z, m);
rep(i, 1, lim){
if (m - i <= n - z){
dfs(z - i + m - i, m, n);
}
}
lim = min(n - z, m);
rep(i, 1, lim){
if (m - i <= z){
dfs(z + i - m + i, m, n);
}
}
}
int main(void){
int n, m;
while (~scanf("%d %d", &n, &m)){
memset(v, 0, sizeof(v));
if (n == -1 && m == -1){break;}
if (n % m == 0){
puts("Yes");
continue;
}
flag = false;
dfs(n, m, n);
if (flag){
puts("Yes");
}else{
puts("No");
}
}
return 0;
}