ACM-ICPC 2018 南京賽區網路預賽__K The Great Nim Game【博弈論+費馬小定理+DP】

Enjoy_process發表於2018-09-06
  •  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;
}

 

相關文章