这是一个句子测试

2
23
2016
0

Contest20160219滚粗记

发现这套题去年暑假做过!

然而依然没有思路。。。

这真是一个伤心的故事。

T1

鉴于BZOJ爆炸的先例,先描述下题面。

给你一棵树,支持:1、修改某个点的权值。2、求点权和最大的一个联通块。

我记得这是道树剖。

然而我只会n2的树形dp和一条链的情况。

%%%小条将此题AC

令dp[u]表示必须选u,u及u的轻儿子构成的子树的最大联通块的点权。

那么只要对于重链上的dp值求最大连续子段和即可得出最终答案。

对于修改,显然只会对top[u]产生影响,那么需要求出点权修改前后的差值来进行修改。

然后不断地更新top即可。

T2

询问n个点n条边的简单无向连通图的个数。

OEIS神题。

通过查询可以获得通项公式:

[tex]\frac{(n-1)!*n^n}{2}*\sum^{n}_{k=3}\frac{1}{(n-k)!*n^k}[/tex]

然后就解决了。(然而在一堆蚂蚁文中我已经彻底晕了)

T3

给出n个白点,每次随机选出一个区间并将区间内的白点染黑,问将白点全部染黑的期望步数。

直接30分状压保平安。。。

当然还有另外一种开黑方法:按照题意随机1亿次取平均值。

令p[i]为i次没有全部染黑的概率。

[tex]ans=\sum^{\infty}_{i=0}p[i][/tex]

没有染黑,必然留下一些白点,不妨设它们的编号分别是a1,a2,……,an

那么只能在[1,a1-1],[a1+1,a2-1],……,[an-1+1,an]中选择。

若这些区间的子区间有A个,对P[i]的贡献就是:

[tex]p=(\frac{2A}{(n+1)*n})^i[/tex]

显然需要容斥,如果白点有奇数个对答案的贡献就是正的,否则就是负的。

对于最终答案的统计,有:

[tex]\sum^{\infty}_{i=0}P[i]=\frac{1}{1-p}[/tex]

那么只要通过dp来求出p就可以了!

【Codes】

#include<cstdio>
#include<algorithm>
#include<cstring>
typedef long long ll;
using namespace std;
const int M=800010;
const int inf=1000000007;
int n,m,i,x,y,ch,opt,edgenum,time,cnt;
int a[M],head[M],vet[M],next[M],flag[M],fa[M],size[M],son[M],top[M],tid[M],space[M],dp[M];
struct node{ll w,l,r,mx;}tree[M];
void addedge(int x,int y){
	vet[++edgenum]=y;
	next[edgenum]=head[x];
	head[x]=edgenum;
}
void dfs(int u,int pre){
	size[u]=1;fa[u]=pre;
	dp[u]=a[u];
	for (int e=head[u];e;e=next[e]){
		int v=vet[e];
		if (v==pre)continue;
		dfs(v,u);
		if (dp[v]>0)dp[u]+=dp[v];
		size[u]+=size[v];
		if (!son[u]||size[v]>size[son[u]])son[u]=v;
	}
}
void Dfs(int u,int ance){
	flag[u]=1;
	tid[u]=++time;top[u]=ance;
	if (son[u]){
		if (dp[son[u]]>0)dp[u]-=dp[son[u]];
		Dfs(son[u],ance);
	}
	for (int e=head[u];e;e=next[e]){
		int v=vet[e];
		if (flag[v])continue;
		space[++cnt]=++time;
		Dfs(v,v);
	}
}
void pushup(int p){
	int l=p<<1,r=p<<1^1;
	tree[p].w=tree[l].w+tree[r].w;
	tree[p].l=max(tree[l].l,tree[l].w+tree[r].l);
	tree[p].r=max(tree[r].r,tree[r].w+tree[l].r);
	tree[p].mx=max(max(tree[p].l,tree[p].r),max(max(tree[l].mx,tree[r].mx),tree[l].r+tree[r].l));
}
void update(int x,int l,int r,int p,int t){
	if (l==r){
		tree[p].w=t;
		tree[p].l=max(t,0);
		tree[p].r=max(t,0);
		tree[p].mx=max(t,0);
		return;
	}
	int mid=l+r>>1;
	if (x<=mid)update(x,l,mid,p<<1,t);
		else update(x,mid+1,r,p<<1^1,t);
	pushup(p);
}
ll Search(int x,int y,int l,int r,int p){
	if (x==l&&y==r)return tree[p].w;
	int mid=l+r>>1;
	if (y<=mid)return Search(x,y,l,mid,p<<1);
		else if (x>mid)return Search(x,y,mid+1,r,p<<1^1);
			else return Search(x,mid,l,mid,p<<1)+Search(mid+1,y,mid+1,r,p<<1^1);
}
ll search(int x,int y,int l,int r,int p){
	if (x==l&&y==r)return tree[p].l;
	int mid=l+r>>1;
	if (y<=mid)return search(x,y,l,mid,p<<1);
		else if (x>mid)return search(x,y,mid+1,y,p<<1^1);
			else return max(search(x,mid,l,mid,p<<1),search(mid+1,y,mid+1,r,p<<1^1)+Search(x,mid,l,mid,p<<1));
}
void Update(int x,int y){
	ll p=search(tid[top[x]],time,1,time,1);
	update(tid[x],1,time,1,dp[x]+y);
	dp[x]+=y;
	ll q=search(tid[top[x]],time,1,time,1);
	if (top[x]!=1)Update(fa[top[x]],q-p);
}
int main(){
	scanf("%d%d",&n,&m);
	for (i=1;i<=n;i++)scanf("%d",&a[i]);
	for (i=1;i<n;i++){
		scanf("%d%d",&x,&y);
		addedge(x,y);
		addedge(y,x);
	}
	dfs(1,-1);
	Dfs(1,1);
	for (i=1;i<=cnt;i++)update(space[i],1,time,1,-inf);
	for (i=1;i<=n;i++)update(tid[i],1,time,1,dp[i]);
	for (i=1;i<=m;i++){
		scanf("%d",&opt);
		if (opt==1){
			scanf("%d%d",&x,&y);
			Update(x,y-a[x]);
			a[x]=y;
		}else printf("%d\n",tree[1].mx);
	}
}
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n,i;
struct bignum{int w[5010];}yi,now,cnt,ans;
bignum operator + (bignum a,bignum b){
	bignum c;
	int l=max(a.w[0],b.w[0]);
	//for (int i=0;i<=l;i++)c.w[i]=0;
	memset(c.w,0,sizeof c.w);
	for (int i=1;i<=l;i++){
		c.w[i+1]=c.w[i+1]+(a.w[i]+b.w[i]+c.w[i])/10000;
		c.w[i]=(a.w[i]+b.w[i]+c.w[i])%10000;
	}
	if (c.w[l+1])c.w[0]=l+1;else c.w[0]=l;
	return c;
}
bignum operator - (bignum a,int b){
	a.w[1]-=b;
	int now=1;
	while (a.w[now]<0)a.w[now+1]-=1,a.w[now]+=10000,now++;
	while (a.w[0]&&!a.w[a.w[0]])a.w[0]--;
	return a;
}
bignum operator * (bignum a,bignum b){
	bignum c;
	//for (int i=0;i<=a.w[0]+b.w[0];i++)c.w[i]=0;
	memset(c.w,0,sizeof c.w);
	for (int i=1;i<=a.w[0];i++)
		for (int j=1;j<=b.w[0];j++){
			c.w[i+j]=c.w[i+j]+(a.w[i]*b.w[j]+c.w[i+j-1])/10000;
			c.w[i+j-1]=(a.w[i]*b.w[j]+c.w[i+j-1])%10000;
		}
	if (c.w[a.w[0]+b.w[0]])c.w[0]=a.w[0]+b.w[0];else c.w[0]=a.w[0]+b.w[0]-1;
	return c;
}
bignum operator / (bignum a,int b){
	for (int i=a.w[0];i>1;i--){
		a.w[i-1]=a.w[i-1]+a.w[i]%b*10000;
		a.w[i]=a.w[i]/b;
	}
	a.w[1]=a.w[1]/b;
	while (a.w[0]&&!a.w[a.w[0]])a.w[0]--;
	return a;
}
void print(bignum a){
	printf("%d",a.w[a.w[0]]);
	for (int i=a.w[0]-1;i;i--)
		if (a.w[i]>=1000)printf("%d",a.w[i]);
			else if (a.w[i]>=100)printf("0%d",a.w[i]);
				else if (a.w[i]>=10)printf("00%d",a.w[i]);
					else printf("000%d",a.w[i]);
	puts("");
}
int main(){
	scanf("%d",&n);
	if (n<=2){puts("0");return 0;}
	yi.w[0]=1;yi.w[1]=1;
	now.w[0]=cnt.w[0]=ans.w[0]=1;
	for (i=1;i<n;i++)now=now+yi;
	cnt=now,now=now+yi;
	int N=n-2;
	bignum Now=now;
	while (N){
		if (N&1)cnt=cnt*Now;
		Now=Now*Now;
		N>>=1;
	}
	cnt=cnt/2;
	now=now-2;
	for (i=3;i<=n;i++){
		cnt=cnt/n*now;
		now=now-1;
		ans=ans+cnt;
	}
	print(ans);
}
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n,i,j,k;
double ans;
double dp[110][10010];
int main(){
	scanf("%d",&n);
	int m=(n+1)*n/2;
	dp[0][0]=1;
	for (i=1;i<=n+1;i++)
		for (j=i;j>=0;j--)
			for (k=(i-j)*(i-j-1)/2;k<=m;k++)dp[i][k]-=dp[j][k-(i-j)*(i-j-1)/2];
	for (i=0;i<m;i++)ans+=dp[n+1][i]/(1-(double)i/m);
	printf("%.4lf\n",ans);
}
Category: 蒟蒻的滚粗记 | Tags: dp 树链剖分 | Read Count: 4160

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com