对SG函数的理解:
自认为sg函数应该算是博弈论中比较经典的东西了。。他几乎可以解决博弈论中的所有问题。你可以将sg函数看作是一个深搜的的过程。而每一堆的石子就相当于图中间的节点。所以说整个sg函数的过程就是在对一个有向无环图进行dfs的过程。
sg函数的具体内容可以用一个公式来表示(虽然我最不喜欢公式,不过我还是得写。不然这没法说清楚):sg(x) =mex{sg(y) : y ∈ F(x)}。其中{}内的是一个集合(只要上过高中都应该知道吧),在:右边的是该集合元素所满足的条件。sg(y)为该元素的值(其实就是一个递归的过程)。重点来了。。mex()函数表示是不在该集合中的最小的非负整数的值。比如mex({1,2,3})=0...mex({0,2,4})=1...mex({})=0..最后得出来的结果中。为0为必败点,不为零必胜点。。F(x)是x能达到的节点。
接下来才是sg函数精妙之处了。假如说是在一个游戏中有多个石子堆该怎么办了。我们只需要把对每个石子堆进行sg函数的调用,将得到的所有的值进行异或。得出来的结果为0则该情形为必败态。否则为必胜态。。
此题求出1e6以内的sg值,超出的另外求。排序,尺取法。
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) {
InputStream inputStream = System.in;
OutputStream outputStream = System.out;
InputReader in = new InputReader(inputStream);
PrintWriter out = new PrintWriter(outputStream);
new Task().solve(in, out);
out.close();
}
}
class Task {
static final long mod=1000000007;
static final int maxn=1000005;
public void solve(InputReader in,PrintWriter out) {
int sg[]=new int[maxn];
int ws[]=new int[maxn];
sg[0]=0;
Arrays.fill(ws, 0);
int a=0,b=0;
for(int i=1;i<=1000000;i++) {
while(a*a<=i&&a<i) {
ws[sg[a]]++;
a++;
}
while(b*b*b*b<i) {
ws[sg[b]]--;
b++;
}
sg[i]=0;
while(ws[sg[i]]!=0) {
sg[i]++;
}
}
int n=in.nextInt();
long d[]=new long[n];
for(int i=0;i<n;i++)
d[i]=in.nextLong();
Arrays.sort(d);
int ans=0;
Arrays.fill(ws,0);
a=0; b=0;
for(int i=0;i<n;i++) {
long c=d[i];
if(c<=1000000)
ans^=sg[(int)c];
else {
while((long)a*a<=c&&a<c) {
ws[sg[a]]++;
a++;
}
while((long)b*b*b*b<c) {
ws[sg[b]]--;
b++;
}
int u=0;
while(ws[u]!=0) {
u++;
}
ans^=u;
}
}
if(ans==0)
out.println("Rublo");
else
out.println("Furlo");
}
class Pair implements Comparable<Pair>{
public int compareTo(Pair arg0) {
return 0;
}
}
}
class InputReader {
public BufferedReader reader;
public StringTokenizer tokenizer;
public InputReader(InputStream stream) {
reader = new BufferedReader(new InputStreamReader(stream), 32768);
tokenizer = null;
}
public String next() {
while (tokenizer == null || !tokenizer.hasMoreTokens()) {
try {
tokenizer = new StringTokenizer(reader.readLine());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return tokenizer.nextToken();
}
public int nextInt() {
return Integer.parseInt(next());
}
public long nextLong() {
return Long.parseLong(next());
}
public double nextDouble() {
return Double.parseDouble(next());
}
public boolean hasNext() {
return new Scanner(System.in).hasNext();
}
}