[2020 China College Student Programming Competition (CCPC)-Network Trial Competition] 1005 Lunch

Topic link: Lunch

Title

There are n piles of stones, each pile of stones li {l_i}liNow there are two people taking turns playing the game. The rules of the game are as follows:

  1. If in the current round, each pile of stones is all 1, then the player loses the game.
  2. Assuming that there is a pile of stones with the number L, the contestant can choose a factor K of L greater than or equal to 2 as the new pile number, and then divide the pile into K piles, each pile LK {\frac{L}{K}}KLStones.

At the end of the game, each pile of stones is all 1, and one person must fail.
Ask whether the first player will win, if it is to output "W", otherwise "L".

answer

This question is obviously a modification of the Nim game. The solution to this type of problem is nothing more than the SG function, so we can first analyze the set of subsequent states, and then try the SG function to find the law.

Obviously, the number of subsequent states of a number L is the number of factors greater than or equal to 2, and the solution is similar to the split Nim.
Assuming the factor is k, each state has LK {\frac{L}{K}}KLK, then the value of the state is LK {\frac{L}{K}}KLSG(K) is XORed.
Each state has an SG value. The SG theorem concludes that SG(L) is the Nim sum of its subsequent states.
Just memoize the SG function and hit the table.

Watch code

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<stack>
#include<vector>
#include<unordered_set>
#include<unordered_map>
using namespace std;

typedef long long ll;
const int maxn=4e4+10;
const int maxm=1e4+10;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int n,m;
int f[maxm];

int sg(int x){
    
    
	if(f[x]!=-1) return f[x];
	unordered_set<int> S;
	vector<int> q;
	for(ll i=2;i<=sqrt(x);++i){
    
    
		if(x%i==0){
    
    
			q.push_back(i);
			if(i*i!=x) q.push_back(x/i);
		}
	}
	q.push_back(x);
	for(int i=0;i<q.size();++i)
	{
    
    
		if(q[i]%2==0) S.insert(0);
		else S.insert(sg(x/q[i]));
	}
	for(int i=0;;++i){
    
    
		if(!S.count(i)) return f[x] = i;
	}
}

int main(void)
{
    
    
	memset(f, -1, sizeof(f));
	f[1]=0;
	for(int i=1;i<=30;i++) cout << i << ' ' << sg(i) << "   ";
}

I think the difficulty of this question lies in finding the pattern
. It was because I didn’t find the pattern in the game that I gg. Uncomfortable~

This time the law is obtained by unique decomposition. The SG value of L is the sum of the powers of prime factors except 2 after the unique decomposition of L. If it is an even number +1, the odd number is not added.

Since the upper limit of L is 1e9, you can preprocess 1 e 9 {\sqrt{1e9}}1e9 Prime numbers within, and then uniquely decompose to get the answer.

Code

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<bitset>
#include<cassert>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<deque>
#include<iomanip>
#include<list>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#include<unordered_set>
#include<unordered_map>
using namespace std;
//extern "C"{void *__dso_handle=0;}
typedef long long ll;
typedef long double ld;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define pii pair<int,int>
#define lowbit(x) x&-x

const double PI=acos(-1.0);
const double eps=1e-6;
const ll mod=1e9+7;
const int inf=0x3f3f3f3f;
const int maxn=4e4+10;
const int maxm=1e4+10;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int n,m;

int prime[maxn+10];
void getprime()
{
    
    
	for(int i=2;i<=maxn;i++)
	{
    
    
		if(!prime[i]) prime[++prime[0]]=i;
		for(int j=1;j<=prime[0]&&i*prime[j]<=maxn;j++)
		{
    
    
			prime[prime[j]*i]=1;
			if(i%prime[j]==0) break;
		}
	}
}
int SG(int x)
{
    
    
	int res=0;
	if(x%2==0) res=1;
	int tmp=x,cnt=0;
	for(int i=1;i<=prime[0];i++)
	{
    
    
		if(tmp%prime[i]==0)
		{
    
    
			while(tmp%prime[i]==0)
			{
    
    
				tmp/=prime[i];
				if(prime[i]!=2) cnt++;
			}
		}
		if(tmp==1) break;
	}
	if(tmp!=1 && tmp!=2) cnt++;
	return cnt+res;
}
int main(void)
{
    
    
	getprime();
	int t;
	scanf("%d",&t);
	while(t--)
	{
    
    
		scanf("%d",&n);
		int res = 0;
		for(int i=0;i<n;++i){
    
    
			int x;
			cin>>x;
			res ^= SG(x);
		}
		if(res) printf("W\n");
		else printf("L\n");
	}
}

Guess you like

Origin blog.csdn.net/weixin_44235989/article/details/108714067