ProjectEuler 306 【sg函数】

题目链接:https://projecteuler.net/problem=306

题意:两个人在玩游戏,一个 1 ∗ n 1*n 1n的纸条,每次可以将连续的2个格子染色,如果一个人无法继续操作就输了,问 1 ≤ n ≤ 1000000 1 \le n \le 1000000 1n1000000中有多少个 n n n使得先手有必胜策略

题解:
注意到染色之后左右独立
易知 s g [ i ] = m e x ( s g [ j − 1 ] , s g [ i − j − 1 ] ) sg[i]=mex(sg[j-1],sg[i-j-1]) sg[i]=mex(sg[j1],sg[ij1]) j为枚举的染色位置
然后将sg函数打出来
发现:
1~n:
在这里插入图片描述
除了第1、2行,其余的开始循环
根据这个可以写出一个模拟的循环程序
a 1 [ ] 、 a 2 [ ] a1[] 、a2[] a1[]a2[]的第一个是为了控制下标

// by Balloons
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() puts("okkkkkkkk")
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)

using namespace std;

typedef long long LL;

const int inf = 1 << 29;

const int a1[]={23333,0,1,1,2,0,3,1,1,0,3,3,2,2,4,0,5,2,2,3,3,0,1,1,3,0,2,1,1,0,4,5,2,7,4,0};
const int a2[]={23333,1,1,2,0,3,1,1,0,3,3,2,2,4,4,5,5,2,3,3,0,1,1,3,0,2,1,1,0,4,5,3,7,4,8};
	
int main(){
	int res=0;
	int n;scanf("%d",&n);
	for(int i=1;i<=min(n,35);i++)if(a1[i])++res;
	if(n>35){
		int j=36;
		while(j<=n){
			for(int i=1;i<=34;i++){
				if(a2[i])++res;
				++j;
				if(j>n){
					break; 
				}
			} 
		}
	}
	printf("%d\n",res);

	return 0;
}

易知 n = 1000000 n=1000000 n=1000000 a n s = 852938 ans=852938 ans=852938
可以bonus: n ≤ 7 e 6 n \le 7e6 n7e6 也可以这样做

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值