1、给定一个数字$N$,从1到100的100个数字中选出$K$个数字(设为集合$S$),然后对$S$进行如下运算:
(1)删除$S$中的某些数字;(可以删除0个数字)
(2)将$S$中的某些数字取为它的相反数;(可以改变0个数字)
(3)对$S$中的数字求和得到$ans$
现在给出一种选择$K$个数的方法使得无论如何操作,$ans eq N$。$1leq N leq 100,1leq K leq 15$
思路:从2开始枚举选择一个数字$x$,使得$N$%$x eq 0$,然后选择$x,2x,3x,...,Kx$。这样的话无论如何操作最后的$ans$都是$x$ 的倍数。但是当$N=60$时$x=7$,这是如果$K=15$,最后会选择105,这是可以特殊处理,把105换成1.因为7的任何倍数加减1都不会是60.
#include <stdio.h> #include <string> #include <stack> #include <vector> #include <string.h> #include <algorithm> #include <assert.h> using namespace std; class WolfCardGame { public: vector<int> createAnswer(int n,int K) { vector<int> ans; for(int i=2;;++i) if(n%i) { for(int j=1;j<=K;++j) ans.push_back(i*j); if(i==7) { ans[K-1]=1; } break; } return ans; } };
2、对于一个有向树(树边是有方向的)$T$,定义$f(T)$表示这样的顶点对的个数:$(u,v)$,存在从$u$到$v$的路径。现在给定一棵$n$个顶点的无向树,给每条边选择一个方向,那么有$2^{n-1}$种方式,计算每种方式产生的有向树的$f$值之和。
思路:考虑树分治。对于现在的树的重心$S$,那么对答案有贡献的顶点对有两种:要么顶点对其中的一个顶点是$S$,要么是跨过$S$的两个顶点。第一种容易计算,因为设另一个顶点是$u$,那么$u$与$S$之间的边的方向是相同的,而其他的边的方向任意,所以设它们之间的边的个数是$x$,那么对答案的贡献是$g(u)=2*2^{n-1-x}=2^{n-x}$。对于第二种,当前遍历的顶点$v$与之前遍历的顶点$u$之间的边方向是相同的,其余的边方向任意。所以设之前遍历的所有的$S$的子树得到的所有的节点的$g$值之和为$K$,$v$和$S$之间边的个数是$y$,那么当前节点的贡献为$h(v)=frac{K}{2^{y}}$.
#include <stdio.h> #include <string> #include <stack> #include <vector> #include <string.h> #include <algorithm> #include <assert.h> using namespace std; const int N=100005; const int mod=1000000007; vector<int> g[N]; int n; int a[N]; int d[N]; int fa[N]; int p[N]; int Pow(int a,int b) { int ans=1; while(b) { if(b&1) ans=(long long)ans*a%mod; a=(long long)a*a%mod; b>>=1; } return ans; } const int base=Pow(2,mod-2); void init() { p[0]=1; for(int i=1;i<N;++i) p[i]=(p[i-1]<<1)%mod; } int h[N]; int aNum; int Son[N],MaxSon[N]; void DFS(int u,int pre) { Son[u]=1; a[++aNum]=u; MaxSon[u]=0; for(int i=0;i<(int)g[u].size();++i) { int v=g[u][i]; if(v!=pre&&!h[v]) { DFS(v,u); Son[u]+=Son[v]; if(Son[v]>MaxSon[u]) MaxSon[u]=Son[v]; } } } int getcenter(int u) { aNum=0; DFS(u,-1); int ans=u,Min=aNum; for(int i=1;i<=aNum;++i) { int v=a[i]; int tmp=max(aNum-MaxSon[v],MaxSon[v]); if(tmp<Min) Min=tmp,ans=v; } return ans; } int ans; void addAns(int x) { ans=(ans+x)%mod; } int CurrentSum; void calAns(int u,int pre,int preSum,int dep) { addAns(p[n-dep]); preSum=(long long)preSum*base%mod; addAns(preSum); CurrentSum=(CurrentSum+p[n-dep])%mod; for(int i=0;i<(int)g[u].size();++i) { int v=g[u][i]; if(!h[v]&&v!=pre) { calAns(v,u,preSum,dep+1); } } } void dfs(int u) { u=getcenter(u); int preSum=0; for(int i=0;i<(int)g[u].size();++i) { int v=g[u][i]; if(!h[v]) { CurrentSum=0; calAns(v,u,preSum,1); preSum=(preSum+CurrentSum)%mod; } } h[u]=1; for(int i=0;i<(int)g[u].size();++i) { int v=g[u][i]; if(!h[v]) dfs(v); } } class TreeWalker { public: int calc(int nn,int A0,int B,int C,int MOD) { n=nn; init(); a[0]=A0; for(int i=1;i<n;++i) a[i]=((long long)a[i-1]*B+C)%MOD; for(int i=1;i<n;++i) { int u=a[i-1]%i; int v=i; g[u].push_back(v); g[v].push_back(u); } dfs(0); return ans; } };