博弈论:
1.公平组合游戏:
若一个游戏满足:
a.两名玩家交替行动。
b.在游戏进程的任意时刻,可以执行的合法行动与轮到哪名玩家无关。
c.不能行动的玩家判负。
则为一个公平组合游戏。
2.状态图:
在公平组合游戏中可以用有向无环图表示状态,p态和n态。p状态表示该状态对于前一个玩家必胜,n状态表示该状态对于后一个玩家必胜。
大部分游戏中,终止状态是p态。任意一个p态,它要么是一个终止状态,要么它所有可以转移到的状态都是n态。而对于任意一个n态,至少有一个后继状态是p态。
3.Nim游戏
n堆石子,第i堆有(a_i)个,两玩家轮流挑选一堆石子,取走若干个,最后不能取的是输家。
对于当前状态 (a=(a_1,a_2...a_n)),如果 (a_1hat{}a_2hat{}...hat{}a_n=0),则为p态,否则为n态。
结论:Nim博弈先手必胜,当且仅当 (a_1hat{}a_2hat{}...hat{}a_n
eq0)。
T1(nim游戏和经典取石子游戏的结合)
对于x的答案,我们将每个数都mod(x+1),并求出异或和。假如异或和为0,则假如Alice取某堆石子的数量超过了余数,Bob可以取同一堆的石子使得余数变回去。如果Alice取的不超过某堆石子的余数,那么游戏变为经典的nim游戏,所以异或和为0先手必败,否则必胜。
所以问题变为求所有可能的x对应的 (a_imod(x+1))的异或和。
50pts。。。
T2
30pts思路:维护三个堆,分别为x能吃的鱼,x不能吃的鱼,已经吃了的鱼。来回倒腾就行。
24pts代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main(){
priority_queue<int>q;
priority_queue<int,vector<int>,greater<int> >l;
priority_queue<int>eat;
int n,a;scanf("%lld",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&a);q.push(a);
}
scanf("%lld",&a);
int chk;
while(a--){
scanf("%lld",&chk);
int x,y;
if(chk==2){
scanf("%lld",&x);
q.push(x);
}
else if(chk==3){
scanf("%lld",&x);
while(q.top()>x){
l.push(q.top());
q.pop();
}
q.pop();
while(!l.empty()){
q.push(l.top());
l.pop();
}
}
else{
int cnt=0;
scanf("%lld%lld",&x,&y);
while(q.top()>=x){
l.push(q.top());
q.pop();
}
while(!q.empty()){
if(x>=y)break;
x+=q.top();
cnt++;
eat.push(q.top());
q.pop();
while(l.top()<x&&!l.empty()){
q.push(l.top());
l.pop();
}
}
if(x>=y)printf("%lld
",cnt);
else printf("-1
");
while(!l.empty()){
q.push(l.top());l.pop();
}
while(!eat.empty()){
q.push(eat.top());eat.pop();
}
}
}
return 0;
}
正解:线段树二分。
T3
40pts:(n^2)暴力显然
100pts:计算范围内倍数数量即可。
#include <iostream>
#include <cstdio>
#include <algorithm>
#define ll long long
using namespace std;
const int mod=1e9+7;
int gcd(int a,int b){
if (a%b==0) return b;
gcd(b,a%b);
}
ll a,b,c,d;
int main(){
scanf ("%lld%lld%lld%lld",&a,&b,&c,&d);
ll ans=0;
for (int i = 1;i <= 999;i++){
for (int j = 1;j <= 999;j++){
if (gcd(i,j)==1){
ll l=max((a-1)/i+1,(c-1)/j+1),r=min(b/i,d/j);
ans=(ans+max((ll)(0),r-l+1)*(i+j))%mod;
}
}
}
printf("%lld
",ans);
return 0;
}