(资料图片仅供参考)
typedef long long LL;const int N = 20;int p[N];int n, m;int main(){ cin >> n >> m; for(int i = 1; i <= m; ++ i) cin >> p[i]; int res = 0; //记录答案 for(int i = 1; i < 1 << m; ++ i){ //遍历2^m-1次,即遍历所有的方案 int t = 1, cnt = 0; //记录当前p的倍数,以及p的个数 for(int j = 1; j <= m; ++ j){ //遍历m位,求出当前方案选取的质数及个数 if(i >> (j - 1) & 1){ cnt ++ ; //选取了当前位的质数,质数加一 if((LL)t * p[j] > n){ //判断质数的倍数是否超出范围 t = -1; break; } t = (LL)t * p[j]; //累乘当前位的质数 } } if(t != -1){ if(cnt % 2) res += n / t; //个数质数位奇数,则取加号 else res -= n / t; //否则取减号 } } cout << res; return 0;}#include #include #include using namespace std;const int N = 110;const int M = 1e4 + 10;int s[N], f[M]; //s[i]存储可以取的石子数,f[i]存储每个状态的sg值,每个状态用当前石子数表示int n, k;//dfs求sg值int sg(int x){ if(f[x] != -1) return f[x]; //记忆化搜索 unordered_set S; //储存可以走到的局面的sg值 for(int i = 1; i <= k; ++ i){ //遍历所有可以取的石子数量 int sum = s[i]; if(x >= sum) S.insert(sg(x - sum)); //将走到的局面的sg值存储 } for(int i = 0; ; ++ i) //从小到大遍历可能的sg值 if(!S.count(i)) //若该sg值是不能达到的sg中的最小值 return f[x] = i; //取该sg值}int main(){ cin >> k; for(int i = 1; i <= k; ++ i) cin >> s[i]; cin >> n; memset(f, -1, sizeof f);//别忘了初始化 int res = 0; while(n -- ){ int h; cin >> h; res = res ^ sg(h); //起点的sg异或值 } if(res) cout << "Yes"; else cout << "No"; return 0;} #include #include #include using namespace std;const int N = 110;int f[N];int n;int sg(int x){ if(f[x] != -1) return f[x];//记忆化 unordered_set s; for(int i = 0; i < x; ++ i) for(int j = 0; j <= i; ++ j) //避免重复,约定第二堆的数量小于等于第一堆 s.insert(sg(i) ^ sg(j)); //两个石子为一个局面,由sg定理:两个石子的sg异或值为当前局面的sg值 for(int i = 0; ; ++ i) //选取不存在的最小的自然数 if(!s.count(i)) return f[x] = i; }int main(){ cin >> n; memset(f, -1, sizeof f); int res = 0; while(n -- ){ int x; cin >> x; res ^= sg(x); } if(res) cout << "Yes"; else cout << "No"; return 0;} 标签:
X 关闭
X 关闭