大致题意:
有n = 500000节点的树, 对于每个节点求距离此节点不超过K (K <= 10)的节点有多少个,把这个n个答案XOR后输出
思路:
题意中的边是通过 “For reading:we have two numbers A and B ,let fai be the father of node i , fa1=0 , fai=(A∗i+B)%(i−1)+1 for i∈[2,N] .”
这样构造出来的,这只是便于快速读入而已,没有给解题带来作用
注意到K最多只有10个, 然后用dp[n][K],代表对于n节点距离不超过K的有多少个节点。用树形DP很好求出在n点下方的不超过K的节点数,对于n点上方
的就不好处理了。
所以用两轮树形DP,一个求dpd[n][K]位于n点下方的距离不超过K的节点数(从下往上dp), 另一个求dpu[n][K] 位于n点上方的距离不超过K的节点数(从上往下dp)。
看代码时不难理解递推公式的
//1560MS 107360K 5712B Java 2015-12-05 23:37:51
import java.util.HashMap;
import java.util.Map;
import java.math.*;
import java.io.BufferedReader;
import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.util.StringTokenizer;
import java.io.PrintWriter;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
InputStream inputStream = System.in;
OutputStream outputStream = System.out;
Scanner in = new Scanner(inputStream);
PrintWriter out = new PrintWriter(outputStream);
TaskE solver = new TaskE();
solver.solve(1, in, out);
out.close();
}
static int ans, ecnt;
static int n, A, K, B;
static class TaskE {
public void solve(int testNumber, Scanner in, PrintWriter out) {
int T = in.nextInt();
while( T-- != 0) {
ecnt = ans = 0;
n = in.nextInt();
K = in.nextInt();
A = in.nextInt();
B = in.nextInt();
int head[] = new int[n + 10], es[] = new int[n + 10];
int nxt[] = new int[n + 10], fa[] = new int[n + 10];
int dpd[][] = new int[n + 10][K + 2], dpu[][] = new int[n + 10][K + 2];
for(int i = 1; i <= n; i ++) head[i] = 0;
for(int i = 2; i <= n; i ++) {
fa[i] =(int)( ((long)A *i + B) % (i - 1) + 1);
add(fa[i], i, es, head, nxt);
}
DFS1(1, dpd, nxt, es, head);
for(int i = head[1]; i != 0; i = nxt[i])
DFS2(es[i], fa, dpd, dpu, nxt, es, head);
int tmp = 0;
for(int j = 0; j <= K; j ++) tmp += dpu[1][j] + dpd[1][j];
ans ^= tmp;
out.println(ans);
out.flush();
}
}
}
static void add(int u, int v, int es[],int head[], int nxt[]) {
es[++ecnt] = v;
nxt[ecnt] = head[u];
head[u] = ecnt;
}
static void DFS1(int u, int dpd[][], int nxt[], int es[], int head[]) {
dpd[u][0] = 1;
for(int i = head[u]; i != 0; i = nxt[i]) {
int v = es[i];
DFS1(v, dpd, nxt, es, head);
for(int j = 1; j <= K; j ++) dpd[u][j] += dpd[v][j - 1];
}
}
static void DFS2(int u,int fa[], int dpd[][], int dpu[][], int nxt[], int es[], int head[]) {
int pa = fa[u];
dpu[u][1] = dpd[pa][0];
for(int i = 1; i < K; i ++)
dpu[u][i + 1] = (dpd[pa][i] - dpd[u][i-1]) + dpu[pa][i];
int tmp = 0;
for(int j = 0; j <= K; j ++) tmp += dpu[u][j] + dpd[u][j];
ans ^= tmp;
for(int i = head[u]; i != 0; i = nxt[i]) DFS2(es[i], fa, dpd, dpu, nxt, es, head);
}
static class pii implements Comparable<pii> {
int X, Y;
pii() {
this.X = 0;
this.Y = 0;
}
pii(int X, int Y) {
this.X = X;
this.Y = Y;
}
public int compareTo(pii a) {
if(this.X - a.X != 0) return this.X - a.X;
else return this.Y - a.Y;
}
}
static class Scanner {
BufferedReader br;
StringTokenizer st;
public Scanner(InputStream in) {
br = new BufferedReader(new InputStreamReader(in));
eat("");
}
private void eat(String s) {
st = new StringTokenizer(s);
}
public String nextLine() {
try {
return br.readLine();
} catch (IOException e) {
return null;
}
}
public boolean hasNext() {
while (!st.hasMoreTokens()) {
String s = nextLine();
if (s == null)
return false;
eat(s);
}
return true;
}
public String next() {
hasNext();
return st.nextToken();
}
public int nextInt() {
return Integer.parseInt(next());
}
public long nextLong() {
return Long.parseLong(next());
}
public double nextDouble() {
return Double.parseDouble(next());
}
public BigInteger nextBigInteger() {
return new BigInteger(next());
}
public int[] nextIntArray(int n) {
int[] is = new int[n];
for (int i = 0; i < n; i++) {
is[i] = nextInt();
}
return is;
}
public long[] nextLongArray(int n) {
long[] ls = new long[n];
for (int i = 0; i < n; i++) {
ls[i] = nextLong();
}
return ls;
}
public double[] nextDoubleArray(int n) {
double[] ds = new double[n];
for (int i = 0; i < n; i++) {
ds[i] = nextDouble();
}
return ds;
}
public BigInteger[] nextBigIntegerArray(int n) {
BigInteger[] bs = new BigInteger[n];
for (int i = 0; i < n; i++) {
bs[i] = nextBigInteger();
}
return bs;
}
public int[][] nextIntMatrix(int row, int col) {
int[][] mat = new int[row][];
for (int i = 0; i < row; i++) {
mat[i] = nextIntArray(col);
}
return mat;
}
public long[][] nextLongMatrix(int row, int col) {
long[][] mat = new long[row][];
for (int i = 0; i < row; i++) {
mat[i] = nextLongArray(col);
}
return mat;
}
public double[][] nextDoubleMatrix(int row, int col) {
double[][] mat = new double[row][];
for (int i = 0; i < row; i++) {
mat[i] = nextDoubleArray(col);
}
return mat;
}
public BigInteger[][] nextBigIntegerMatrix(int row, int col) {
BigInteger[][] mat = new BigInteger[row][];
for (int i = 0; i < row; i++) {
mat[i] = nextBigIntegerArray(col);
}
return mat;
}
}
}