今天下午,我们队做了Pku Campus 2010,还算可以4个1y,做了6题,罚时挺少的。过了A,C,D,E,G,H    ^_^

   A 我当时找规律的,发现有递推式,然后得推O(1)公式才能过...    1Y
   Poj 3761 找规律  别人有推公式的

#include
<cstdio>
#include
<cstring>
#include
<algorithm>
#include
<vector>
#include
<queue>
#include
<map>
#include
<cmath>
#include
<cstdlib>
#include
<iostream>

using namespace std;

const int INF = 1000000000;
const int MAXN = 1000001;
const int MOD = 20100713;

void bruteForce()
{
    
for(int n = 1 ; n < 10 ; n++)
    
{
        vector
<int> vt;
        
for(int i = 0 ; i < n ; i++)
            vt.push_back(i);
        
int cnt[10= {0};
        
do
        
{
            vector
<int>_vt(vt);
            
//bubble sort
            int round = 0;
            
for(int i = 0 ; i < n ; i++ , round++)
            
{
                
bool flag = false;
                
for(int j = 1 ; j < n ; j++)
                    
if(vt[j] < vt[j-1])
                    
{
                        swap(vt[j
-1],vt[j]);
                        flag 
= true;
                    }

                
if(flag == false)break;
            }

            cnt[round]
++;
            vt 
= _vt;
        }

        
while( next_permutation(vt.begin() , vt.end()) );
        printf(
"n   %d:\n",n);
        
for(int i = 0 ; i < n ; i++)
            printf(
"%d %d\n",i,cnt[i]);
        puts(
"");
    }

}

/*
 k\ n  1   2   3    4   5   6
    0   1   1   1   1   1   1
    1   0   1   3   7  15  31
    2       0   2  10  38  130
    3           0  6   42  222
    4              0   24  216
    5                  0   120

 可以发现:
                                          k
 dp[n,k] = k*dp[n-1,k] + ∑dp[n-1,j]
                                           0
 这样子计算是O(n*k)的,TLE ,需要O(1)的公式
    dp[n,0] = 1
    dp[n,1] = 2^(n-1) - 1
 自然推出
    dp[n,2] = 2dp[n-1,2] + dp[n-1,2] + dp[n-1,1] + dp[n-1,0]
    = 3dp[n-1,2] + 2^(n-2)
 这个可以用特征方程推出dp[n,2] = 2*3^(n-2) - 2^(n-1)
 同理,就能知道
     dp[n,3] =3dp[n-1,3] + dp[n-1,3] + dp[n-1,2] +dp[n-1,1]+dp[n-1,0]
    = 4dp[n-1,3] +  2*3^(n-3)
 推出dp[n,3] = 2*3*4^(n-3) - 2*3^(n-2)
 对比猜想
    dp[n,0] = 1
    dp[n,1] = 2^(n-1) - 1
    dp[n,2] = 2*3^(n-2) - 2^(n-1)
    dp[n,3] = 2*3*4^(n-3) - 2*3^(n-2)
    
    dp[n,k] = k! * ( (k+1)^(n-k) - k^(n-k))

    
http://roba.rushcj.com/?p=491
    下面的留言那里有人推公式的 Orz
 
*/



long long ipow(long long a, int n)
{
    
if(n==0)return 1;
    
if(n==1)return a % MOD;
    
long long ans = ipow(a,n/2);
    ans 
= ans * ans % MOD;
    
if(n&1)ans = ans*a%MOD;
    
return ans;
}


long long f[MAXN];

int main()
{

#ifdef ONLINE_JUDGE
#else
   
// freopen("in", "r", stdin);
   
// freopen("out", "w", stdout);
#endif

    
//bruteForce();

    
//需要先预处理阶乘
    f[0= 1;
    
for(int i = 1 ; i < MAXN ;i++)
        f[i] 
= f[i-1* i % MOD;
    
int n , k , T;
    
for(scanf("%d",&T) ; T-- ; )
    
{
        scanf(
"%d%d",&n,&k);
        printf(
"%lld\n" , f[k] * ((ipow(k+1,n-k) - ipow(k,n-k)) + MOD) % MOD);
    }

    
return 0;
}




   C 树形dp 1Y
   Poj 3763 ★★★
/*
    题意:给出一棵树,问添加最少的边使得每个点走出一个哈密顿回路(每个点只走一次,且边不重复走)
    树形dp,一开始状态设计不清晰,想着既然是环,就定义把整棵子树搞成环的最小代价,发现需要多一个搞成链的状态
    其实,只需要定义把子树搞成链的最小代价即可
    dp[u]把子树搞成链,u为链的一个端点
    _dp[u]把子树搞成链,u为链的中间点

    处理一棵树时,其实就是串链子,把子树的链串起来
    对于dp[u],可以选择dp[v],_dp[v] ,还有要把num个儿子串起来,需要加num-1条边串起来
    即∑min{dp[v],_dp[v]} + num - 1   但这样子有可能都是_dp[v],即根u不与子树连起来,
    本来就该选择一个_dp[v]去掉,加上dp[v] 或者直接对某个_dp[v]+1,发现效果都是一样的,最多只增加1,
    所以不用枚举选择一个_dp[v]去掉换上dp[v],直接加上1即可!

    同理,对于_dp[u] ,∑min{dp[v],_dp[v]} + num - 1
    看选了多少个_dp[v] ,不够的话要补链

    最后的答案是对dp[1],_dp[1]补成环
    dp[1] , 即1是一个链的端点,就要看之前选了多少个dp[v]了,多于1个的话,就不用加边了
    _dp[1] 就得加多一条边,连接两个子树

 
*/


#include
<cstdio>
#include
<cstring>
#include
<algorithm>
#include
<vector>
#include
<queue>
#include
<map>
#include
<cmath>
#include
<cstdlib>
#include
<iostream>

using namespace std;

const int INF = 1000000000;
const int MAXN = 100010;

struct Edge
{
    
int v;
    Edge 
*next;
}
;

Edge 
*E[MAXN] , *pE , edges[MAXN*2];
int dp[MAXN] , _dp[MAXN];
int cnt[MAXN];

void add(int u ,int v)
{
    pE
->= v;
    pE
->next = E[u];
    E[u] 
= pE++;
}


void dfs(int u, int p)
{
    cnt[u] 
= 0;
    
int num = 0 , tot = 0;
    
for(Edge *it = E[u] ; it ; it = it->next)
    
{
        
int v = it->v;
        
if(v == p)continue;
        num 
++;
        dfs(v,u);
        
if(dp[v] <= _dp[v])
        
{
            cnt[u] 
++;
            tot 
+= dp[v];
        }

        
else tot += _dp[v];
    }

    
if(num == 0)dp[u] = _dp[u] = 0;
    
else
    
{
        dp[u] 
= num - 1 + tot;
        _dp[u] 
= num - 2 + tot;
        
if(cnt[u] < 1)dp[u] ++;
        
if(cnt[u] < 2)_dp[u] += (2-cnt[u]);
    }

  
//  printf("%d %d %d %d\n",u,cnt[u],dp[u],_dp[u]);
}


int main()
{

#ifdef ONLINE_JUDGE
#else
    freopen(
"in""r", stdin);
#endif

    
int n;
    
while~scanf("%d",&n) )
    
{
        pE 
= edges;
        
for(int i = 1;  i <= n ; i++)
            E[i] 
= NULL;
        
int u ,v;
        
for(int i = 1 ; i < n ;i++)
        
{
            scanf(
"%d%d",&u,&v);
            add(u,v);
            add(v,u);
        }

        dfs(
1,1);
        
int A = dp[1+ (cnt[1<= 1);//写成cnt[u]错了一次  #_#
        int B = _dp[1+ 1;
        printf(
"%d\n",min(A,B));
    }

    
return 0;
}




   D 预处理dist[] 用Trie树加速枚举查找  1TLE 1 RE 1 WA 
   Poj 3764 ★★★★ 树路径上异或值最大   
/*
    题意 : 求一棵树上某条路径,其边权的异或值最大
    比赛时我想到先以0为根dfs出每个点到0的路径的异或值dist[u],  然后要求两点间路径的异或值就是 dist[a] ^ dist[b]
    这样问题就转化为怎么在这个dist[]里面找出最大的异或值、自身值

    起初的一个贪心的思路:
    最高位为1的肯定要选,而且不能被异或掉,所以按照最高位来分组
    这样就枚举最高的那一组的那些值去跟其它组的值异或,找最大
    同时,对于x,要找y,使得异或后增大的话,找的只需是x的最左的0那一位,但y该位是1的,这样必定会增大值
    如 x = 1101101  , 找最高位为4的那一组,该组为空的话就找第1组,然后只需枚举这一组的y跟x的异或值即可

    但这样子做还是会超时,这样的枚举只会优化常数

    比赛时zeus提出用Trie树做,这样子枚举时复杂度就很低了,果然,在Trie树走就可以了

    做法是,对剩余那些组(最高位那组不用加进去,它是用来枚举的)建立Trie树
    然后对最高位那组的所有值在Trie树上走,先选择使得异或值为1的点走,没有就只好走异或值为0的了

    原来《浅谈信息学竞赛中的“0”和“1”》有提到建立Trie树搞

    “对某个值s,要查找n个权值中和其异或最大的,trie树确实是最佳选择”
 
*/

#include
<cstdio>
#include
<cstring>
#include
<algorithm>
#include
<vector>
#include
<queue>
#include
<map>
#include
<cmath>
#include
<cstdlib>
#include
<iostream>

using namespace std;

const int INF = 1000000000;
const int MAXN = 100010;


struct Edge
{
    
int v , w;
    Edge 
*next;
}
;

Edge 
*E[MAXN] , *pE , edges[MAXN*2];

struct Node
{
    Node 
*ch[2];
}
;

Node 
*pN , nodes[MAXN*31];

Node 
*newNode()
{
    
for(int i = 0 ; i < 2; i++)
        pN
->ch[i] = NULL;
    
return pN++;
}


int dist[MAXN];

void dfs(int u , int p ,int W)
{
    dist[u] 
= W;
    
for(Edge *it = E[u] ; it ; it = it->next)
    
{
        
int v = it->v , w = it->w;
        
if(v == p)continue;
        dfs(v,u,w
^W);
    }

}


void add(int u , int v , int w)
{
    pE
->= v;
    pE
->= w;
    pE
->next = E[u];
    E[u] 
= pE++;
}



void insert(Node *root ,int len , int x)
{
    
if(len < 0)return;
    
bool who = (x>>len)&1 ;
    
if(root->ch[who] == NULL )root->ch[who] = newNode();
    insert(root
->ch[who] , len-1 , x);
}


int gao(Node *root , int len ,int x)
{
    
if(root == NULL)return x;
    
if(len < 0 )return x;
    
bool who = (x>>len)&1;
    who 
^= 1;
    
if(root->ch[who] == NULL )who ^= 1;
    
return gao(root->ch[who] , len-1 , who ? x ^ (1<<len) : x );
}


int main()
{

#ifdef ONLINE_JUDGE
#else
    freopen(
"in""r", stdin);
#endif

    
int n ;
    
while~scanf("%d",&n) )
    
{
        pE 
= edges;
        pN 
= nodes;
        
for(int i = 0 ; i< n ; i++)
            E[i] 
= NULL;

        
int u ,v ,w;
        
for(int i =1 ;i < n ; i++)
        
{
            scanf(
"%d%d%d",&u,&v,&w);
            add(u,v,w);
            add(v,u,w);
        }


        dfs(
0,0,0);

        vector
<int> vt[32];
        
for(int i = 0 ; i < n ; i++)
        
{
            
if(dist[i] == 0)continue;
            
for(int j = 30 ; j >= 0 ; j--)
            
{
                
if( dist[i] & (1<<j) )
                
{
                    vt[j].push_back(dist[i]);
                    
break;
                }

            }

        }


        
int  high = 30;
        
while(high >=0 && vt[high].size() == 0) high--;
        
if(high < 0)
        
{
            puts(
"0");
        }

        
else
        
{
            
            Node 
*root = newNode();//insert all the highest < high
            for(int i = high - 1 ; i >= 0 ; i--)
            
{
                
for(int j = 0 , jsize = vt[i].size() ; j < jsize ; j++)
                
{
                    insert(root , 
30 , vt[i][j]);
                }

            }

            
            
int ans = 0 , size = vt[high].size();
            
for(int i = 0 ; i < size ; i++)
            
{
                
int x = vt[high][i] ;
                ans 
= max(ans , x);
                ans 
= max(ans , gao(root , 30 , x) );
            }

            printf(
"%d\n" ,ans);
        }

    }

    
return 0;
}




   E,G,H 略


   更详细的报告见:
   http://blog.csdn.net/yuhailin060/archive/2010/05/10/5576255.aspx
   http://roba.rushcj.com/?p=491