ACM-ICPC 2018 南京赛区网络预赛__K The Great Nim Game【博弈论+费马小定理+DP】

  •  1500ms
  •  131072K

Nim is a famous game as you know. Nim is a 2-player game featuring several piles of stones. Players alternate turns, and on his/her turn, a player's move consists of removing one or more stones from any single pile. Play ends when all the stones have been removed. The first player who can't remove is declared as the loser.

Now you want to play the Great Nim Game. In the other words, you want to choose several (0 ~ N) pile(s) from N piles of stones. You want know how many choices you have making sure that the first player must win. They both try their best (optimal strategy) to win through the game.

Input

The first line contains two numbers N x1​, denoting the number of piles and the number of stones in the first pile.

The second line contains five integers a, b, c, d, e

The third line contains one integer kk, denoting a function

f(x)=
(ax^4+bx^3+cx^2+dx^1+e - 1)%k+1.

With these, you can figure out the number of stones in the i-th pile xi​=f(xi−1​)(1<i≤N)

It is guaranteed that

1<N<1010000000,
0<x1​≤k,0≤a,b,c,d,e<2^12,
a+b+c+d+e>0,0<k<2^12.

Output

Print the number of solutions making sure the first player must win. The answer may be very large, so you should output it mod 1e9+7 (% 1000000007).

Hint

In the first sample, there are 1,2,3,4,5 stones in the 1-st, 2-nd, 3th, 4th, 5th pile. You can figure out there are exactly 4 choosing ({1,2,3}{1,4,5}{2,3,4,5}{}(empty, you choose zero pile)) ways that make first-hand player must lose, so the answer is 2^5-4=2825−4=28.

If x is in range (1<=x<= k), f(x)(1≤x≤k),f(x) must be in range (1≤f(x)≤k), too.

样例输入1

5 1
0 0 0 1 1
16

样例输出1

28

样例输入2

100000000000000000000 1
0 0 0 1 1
4095

样例输出2

394326889

样例输入3

100000000000000000000 1
1 0 0 1 1
4095

样例输出3

933180537

题目来源

ACM-ICPC 2018 南京赛区网络预赛

参考博客:https://blog.csdn.net/nudt_spy/article/details/82453579

AC的C++代码:

#include<iostream>
#include<string>
#include<cstring>

using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int N=4100;
bool flag[N];//vis[i]记录数i是否出现
int X[N];//记录X[i]的值 
int dp[2][N]; 

ll f(ll x,ll n)
{
	ll res=1;
	while(n>0){
		if(n&1)
		  res=res*x%mod;
		x=x*x%mod;
		n>>=1;
	}
	return res;
}

int main()
{
	string s;
	ll a,b,c,d,e,k,x;
	while(cin>>s>>x>>a>>b>>c>>d>>e>>k){
		ll t=0; 
		int num=0;//num记录能出现多少个不同的x 
		for(int i=0;i<s.length();i++){
			t=(t*10+(s[i]-'0'))%(mod-1);
			if(num<=4096)
			  num=num*10+(s[i]-'0');
		}
		memset(flag,false,sizeof(flag));
		memset(dp,0,sizeof(dp)); 
		X[1]=x;//X1为x 
		flag[x]=true;//x这个数出现了
		for(int i=2;i<=num;i++){//计算这num个不同的x值 
		  int f=X[i-1];
		  X[i]=(a*f*f*f*f+b*f*f*f+c*f*f+d*f+e-1)%k+1;
//如果X[i]这个数已经出现了那么后面的x都是已经出现的数了,这时就跳出 
		  if(flag[X[i]]){
		  	num=i-1;
		  	break;
		  }
		  else//如果没出现就标记
		    flag[X[i]]=true;  
		}
		dp[0][0]=1;
		int x=0,y=1;
		for(int i=1;i<=num;i++,swap(x,y))//考虑这num个不同的数
		  for(int j=0;j<N;j++)
		    dp[y][j]=(dp[x][j^X[i]]+dp[x][j])%mod;
		ll ans=0;
		for(int j=1;j<4096;j++)
		  ans=(ans+dp[x][j])%mod;
		t=(t-num%(mod-1)+(mod-1))%(mod-1);
		cout<<ans*f(2,t)%mod<<endl; 
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值