2020CCPC Network Competition 1005 Lunch (Deformed Nim Game)

Insert picture description here
Question: Given you n pieces of chocolate, the length of each piece of chocolate is l[i], two people take turns to operate, each operation selects a factor of the current length l greater than or equal to 2, and then divide the chocolate into l/factor(l) block, when all the chocolates become 1, the person who performs the operation at this time will lose the game. After asking you the current n and l[i] of each chocolate, the first hand will lose Still win.

Idea: When you see whether the first mover is winning or losing, you can think of it as a game problem. Then we can think that if a length is divided into an even number of chocolate bars, and the number of operations added is an even number, then it will not change the win-loss relationship in the current state. And if it is an odd number of chocolate bars, the relationship between winning and losing in the current state will change.
And because we said that adding an even number does not contribute to the win-loss relationship, so if there are multiple 2s in this factor, we only need to count one, because the contribution of more 2s is the same as a 2’s. Then calculate the number of its prime factors, which is the sum of the powers of each prime factor under the prime factor decomposition.
This is equivalent to replacing a piece of chocolate with the number of prime factors it contains, because these prime factors are individuals that do not affect each other, and they can be regarded as each stone in a stone. Therefore, the problem is It has become the form of a Nim game, and the answer can be obtained by calculating the exclusive or sum of their prime factors.

If MAXN is too large, it will time out. 5e4 is enough.
Code:

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
const int MAXN = 5e4+7;//筛素因子打到 根号N即可
int prime[MAXN],cnt;
bool vis[MAXN];
//考虑质因数分解
void Prime()//欧拉筛求一下质数
{
    
    
	for(int i = 2;i < MAXN;i ++){
    
    
		if(!vis[i])
			prime[++cnt] = i;
		for(int j = 1;j <= cnt&&prime[j]*i < MAXN;j ++){
    
    
			vis[prime[j]*i] = 1;
			if(i % prime[j] == 0)
				break;
		}
	}
}
//直接因数分解 会超时 所以先用线性筛 把素数处理一下 然后再直接用素因数筛
//因为先把合数因子去掉了 所以简单的质因子分解 是遍历所有根号n前面的数 但是这个题会超时 所以就先打出素因子直接处理素因子即可 
int a[17],num[17];

int main()
{
    
    
	int T,n;
	Prime();
	scanf("%d",&T);
	while(T--){
    
    
		memset(num,0,sizeof(num));
		scanf("%d",&n);
		for(int i = 1;i <= n;i ++){
    
    
			scanf("%d",&a[i]);
		}
		int cot = 0;
		int ans = 0;
		for(int i = 1;i <= n;i ++){
    
    
			if(a[i]%2 == 0) num[i]++;//因数2的贡献只计算一次 因为他并不会改变 当前的胜负关系 所以多个和一个的作用效果是一样的
			while(a[i]%2 == 0){
    
    
				a[i] >>= 1;
			}
			for(int j = 1;j <= cnt && prime[j] <= a[i];j ++){
    
    
				while(a[i]%prime[j] == 0){
    
    
					num[i]++;
					a[i] /= prime[j];
				}
			}
			if(a[i] > 1) num[i]++;//大于1就还要再分解一次
			ans ^= num[i];
		}
		if(ans) puts("W");
		else puts("L");
	}
	return 0;
}

Guess you like

Origin blog.csdn.net/weixin_45672411/article/details/108714965