11.2 正睿停课训练 Day15


2018.11.2 正睿停课训练 Day15

时间:3.5h
期望得分:100+20+20
实际得分:100+20+0

比赛链接

A 郁闷的小G(二分)

题目链接

//二分。
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
typedef long long LL;

inline LL read()
{
	LL now=0;register char c=gc();
	for(;!isdigit(c);c=gc());
	for(;isdigit(c);now=now*10+c-'0',c=gc());
	return now;
}
inline bool Check(LL x,LL a,LL b,LL c,LL d,LL e)
{
	if(a<x) b-=x-a;
	if(e<x) d-=x-e;
	if(b<0||d<0) return 0;
	LL tmp=b+d;
	if(c<x) c+=tmp;
	return c>=x;
}

int main()
{
	LL a=read(),b=read(),c=read(),d=read(),e=read();
	LL l=0,r=2e18,mid,ans=0;
	while(l<=r)
		if(Check(mid=l+r>>1,a,b,c,d,e)) ans=mid,l=mid+1;
		else r=mid-1;
	printf("%lld
",ans);

	return 0;
}/*
2 2 1 2 2
100 100 100 0 0
*/

B 小G的树(树形DP)

题目链接

求树的直径需要用到子树最长链与子树内的最大直径,都存下来就好了。
(f[i][j][k])表示当前为点(i)(i)子树最长链长度为(j)(i)子树内最大直径为(k),的概率(直径不一定过点(i))。
转移(O(n^4))就行了。
概率(frac 12)可以最后乘,也就是两种可能的概率都算做(1)。同时存的数不会超过(2^{60}),所以可以用longlong。
最后乘(frac{1}{2^{n-1}}),因为每条边的概率都乘了(2)

//0ms	1080kb
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define gc() getchar()
typedef long long LL;
const int N=62;

int Enum,H[N],nxt[N<<1],to[N<<1],D[N];
LL f[N][N<<1][N<<1];

inline int read()
{
	int now=0;register char c=gc();
	for(;!isdigit(c);c=gc());
	for(;isdigit(c);now=now*10+c-'0',c=gc());
	return now;
}
inline void AE(int u,int v)
{
	to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;
	to[++Enum]=u, nxt[Enum]=H[v], H[v]=Enum;
}
void Merge(int x,int v,int d1,int d2,int d3,int d4)
{
	static LL g[N<<1][N<<1];

	LL (*fx)[N<<1]=f[x],(*fv)[N<<1]=f[v];
	LL tmp,tmp2;
	for(int a=0; a<=d1; ++a)
		for(int b=a; b<=d2; ++b)
			if((tmp=fx[a][b]))
				for(int c=0; c<=d3; ++c)
					for(int d=c; d<=d4; ++d)
					{
						if(!fv[c][d]) continue;
						tmp2=tmp*fv[c][d];
						g[std::max(a,c+1)][std::max(std::max(b,d),a+c+1)]+=tmp2,
						g[std::max(a,c+2)][std::max(std::max(b,d),a+c+2)]+=tmp2;
					}
	int l1=std::max(d1,d3+2),l2=std::max(std::max(d2,d4),d1+d3+2);
	for(int i=0; i<=l1; ++i)
		for(int j=i; j<=l2; ++j) fx[i][j]=g[i][j], g[i][j]=0;
}
int DFS(int x,int fa)
{
	int mxd=0,dia=0; f[x][0][0]=1;
	for(int i=H[x],v,d; i; i=nxt[i])
		if((v=to[i])!=fa)
		{
			d=DFS(v,x), Merge(x,v,mxd,dia,d,D[v]);
			dia=std::max(dia,std::max(D[v],mxd+d)), mxd=std::max(mxd,d);
		}
	return D[x]=dia, mxd+2;
}

int main()
{
	int n=read();
	for(int i=1; i<n; ++i) AE(read(),read());
	int d=DFS(1,1);
	double ans=0;
	for(int i=0; i<=d; ++i)
		for(int j=i; j<=D[1]; ++j) ans+=1.0*f[1][i][j]*j;
	printf("%.10lf
",ans/(1ll<<n-1));

	return 0;
}

C 数的距离(思路)

题目链接

原题:HDU5812

对于(dis(x,y)),把(x,y)质因数分解后(令(x=prod_{i=1}^k p_i^{a_i},y=prod_{i=1}^k p_i^{b_i})),则(dis(x,y)=sum_{i=1}^k |a_i-b_i|)
实际上我们可以去掉(x,y)公共的部分,即令(f(x)=x的质因子个数),则(dis(x,y)=f(frac{x}{gcd(x,y)})+f(frac{y}{gcd(x,y)}))
(f)可以线性筛预处理,即(f(frac{x}{gcd(x,y)}))可以直接得到。然后我们可以枚举(x)的约数(d)作为(gcd(x,y)),然后求(min{f(frac yd)}(y在集合中))

不妨在插入(y)时,也枚举(y)的每个约数(d),然后更新(g(d)=min{g(d),f(frac yd)})(g(d))表示(f(frac yd)(y在集合中))的最小值。
这样就可以(O(1))(min{f(frac yd)})了。

但是还有删除操作,我们需要维护(g(d))的最小值。
注意到(f(x))不会超过(20),且我们只关心(f(frac yd))的大小,所以可以用(cnt[d][t])表示(g(d))中满足(g(d)=t)(y)的个数,用一个二进制数(s[d])表示(g(d))中每个值的存在性。这样就可以(O(1))更新(g(d)),并在查询时直接用位运算找到最小的(g(d))
(事实上用不到(f)数组,因为只需要在枚举约数的时候算下个数就行了)

质因数种类是最多(7)个,但不代表就是(2,3,5,7,11,13,17)这些啊。。
可以处理出每个数的一个质因数(p)(n)每次直接除(p[n]),就不用枚举质数了。

另外看到这个就想到(k)维曼哈顿距离。。最大好像能做吧(就是复杂度有点大),求最小距离是不是不能做啊。。

//646ms	87836kb
#include <cstdio>
#include <cctype>
#include <vector>
#include <algorithm>
//#define gc() getchar()
#define MAXIN 300000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
const int N=1e6+3,INF=1e9;//P[7]={2,3,5,7,11,13,17};

int Opt,Ans,A[7],P[7],p[N],cnt[N][20],s[N];//A[N][7],P[N][7] //卡我内存还行 
char IN[MAXIN],*SS=IN,*TT=IN;

inline int read()
{
	int now=0;register char c=gc();
	for(;!isdigit(c);c=gc());
	for(;isdigit(c);now=now*10+c-'0',c=gc());
	return now;
}
void Init(const int n)
{
	static int P[N>>3];
	static bool not_P[N];
	for(int cnt=0,i=2; i<=n; ++i)
	{
		if(!not_P[i]) P[++cnt]=i, p[i]=i;
		for(int j=1,v; j<=cnt&&(v=i*P[j])<=n; ++j)
		{
			not_P[v]=1, p[v]=P[j];
			if(!(i%P[j])) break;
		}
	}
}
int Div(int x)
{
	int lim=-1,cnt;
	while(x!=1)
	{
		P[++lim]=p[x], cnt=0;
		while(!(x%P[lim])) ++cnt, x/=P[lim];
		A[lim]=cnt;
	}
	return lim;
}
void DFS(int x,int sum,int d)
{
	if(x==-1)
	{
		switch(Opt)
		{
			case 0: if(++cnt[d][sum]==1) s[d]^=1<<sum; break;
			case 1: if(--cnt[d][sum]==0) s[d]^=1<<sum; break;
			case 2: if(s[d]) Ans=std::min(Ans,sum+__builtin_ctz(s[d])); break;
		}
		return;
	}
	for(int i=0; i<=A[x]; ++i)
		DFS(x-1,sum+A[x]-i,d), d*=P[x];
}

int main()
{
	Init(1000000);
	for(int x,tot=0,Q=read(); Q--; )
	{
		Opt=read()-1, x=read();
		if(Opt==2)
			if(tot) Ans=INF;
			else {puts("-1"); continue;}
		else if(cnt[x][0]^Opt) continue;

		DFS(Div(x),0,1);
		switch(Opt)
		{
			case 0: ++tot; break;
			case 1: --tot; break;
			case 2: printf("%d
",Ans==INF?-1:Ans); break;
		}
	}
	return 0;
}

考试代码

B

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define gc() getchar()
#define eps 1e-10
typedef long long LL;
const int N=64;

int n,Enum,H[N],nxt[N<<1],to[N<<1],dgr[N];
double f[N][N];

inline int read()
{
	int now=0;register char c=gc();
	for(;!isdigit(c);c=gc());
	for(;isdigit(c);now=now*10+c-'0',c=gc());
	return now;
}
inline void AE(int u,int v)
{
	++dgr[v], to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;
	++dgr[u], to[++Enum]=u, nxt[Enum]=H[v], H[v]=Enum;
}
int DFS(int x,int fa)
{
	if(dgr[x]==1&&x!=fa)
		for(int i=0; i<=2*n; ++i) f[x][i]=1;
	for(int i=H[x],v; i; i=nxt[i])
		if((v=to[i])!=fa)
		{
			DFS(v,x);
			for(int d=1; d<=2*n; ++d)
			{
				if(f[x][d]<eps) f[x][d]=1;
				f[x][d]*=(f[v][d-1]*0.5+(d>1?f[v][d-2]*0.5:0));
			}
			
		}
	for(int i=0; i<=2*n; ++i) printf("f[%d][%d]=%.5lf
",x,i,f[x][i]);
}

int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);

	n=read();
	for(int i=1; i<n; ++i) AE(read(),read());
	double ans=0; int cnt=0;
	for(int x=1; x<=n; ++x)
	{
		if(dgr[x]>1) continue;
		++cnt;
		for(int i=1; i<=n; ++i)
		{
			f[i][0]=0;
			for(int j=1; j<=2*n; j+=4) f[i][j]=f[i][j+1]=f[i][j+2]=f[i][j+3]=0;
			f[i][2*n-2]=f[i][2*n-1]=f[i][2*n]=0;
		}
		printf("
now:%d
",x);
		DFS(x,x);
		for(int i=1; i<=2*n; ++i) ans+=(f[x][i]-f[x][i-1])*i, printf("ans+=%.5lf*%d=%.5lf
",f[x][i]-f[x][i-1],i,(f[x][i]-f[x][i-1])*i);
	}
	printf("%.10lf
",ans);
	printf("%.10lf
",ans/cnt);

	return 0;
}/*
5
1 2 2 3 3 4 4 5
4
1 2 1 3 1 4
7
1 2 2 3 3 4 3 5 4 6 4 7
*/

C

#include <set>
#include <queue>
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
#define MAXIN 300000
//#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
typedef long long LL;
const int N=1e6+5,P[7]={2,3,5,7,11,13,17};//7

int A[N][7],L[N],R[N];
bool vis[N],ins[N];
std::multiset<int> st[130];
char IN[MAXIN],*SS=IN,*TT=IN;

inline int read()
{
	int now=0;register char c=gc();
	for(;!isdigit(c);c=gc());
	for(;isdigit(c);now=now*10+c-'0',c=gc());
	return now;
}
inline void Div(int x)
{
	vis[x]=1;
	for(int s=x,i=0; i<7; ++i)
		if(!(x%P[i]))
		{
			int cnt=1; x/=P[i];
			while(!(x%P[i])) ++cnt, x/=P[i];
			A[s][i]=cnt;
		}
}

int main()
{
//	freopen("ex_number1.in","r",stdin);
//	freopen(".out","w",stdout);

	int Q=read(); const int all=1<<7;
//	for(int s=0; s<all; ++s) st[s].insert(-1),st[s].insert(100000000);
	for(int x,tot=0,ed=0; Q--; )
	{
		switch(read())
		{
			case 1:
			{
				if(ins[x=read()]) break;
				ins[x]=1, ++tot;
				if(!vis[x]) Div(x);
				R[ed]=x, L[x]=ed, ed=x;
				break;
			}
			case 2:
			{
				if(!ins[x=read()]) break;
				ins[x]=0, --tot;
				L[R[x]]=L[x], R[L[x]]=R[x];
				if(x==ed) ed=L[x];
				break;
			}
			case 3: 
			{
				x=read();
				if(!tot) {puts("-1"); break;}
				if(!vis[x]) Div(x);
				int *a=A[x],ans=1e9;
				for(int i=R[0]; ; i=R[i])
				{
					int sum=0;
					for(int j=0; j<7; ++j) sum+=std::abs(a[j]-A[i][j]);
					ans=std::min(ans,sum);
					if(i==ed) break;
				}
				printf("%d
",ans);
				break;
			}
		}
	}
//	return 0;
	for(int x,tot=0,ed=0; Q--; )
	{
		switch(read())
		{
			case 1:
			{
				if(ins[x=read()]) break;
				ins[x]=1, ++tot;
				if(!vis[x]) Div(x);
				int *a=A[x];
				printf("A[%d]: ",x); for(int i=0; i<7; ++i) printf("%d ",a[i]); puts("");
				for(int s=0; s<all; ++s)
				{
					int sum=0;
					for(int i=0; i<7; ++i)
						sum+=(s>>i&1?a[i]:-a[i]);
					st[s].insert(sum);
					printf("Insert(%d,%d)
",s,sum);
				}
				break;
			}
			case 2:
			{
				if(!ins[x=read()]) break;
				ins[x]=0, --tot;
				int *a=A[x];
				for(int s=0; s<all; ++s)
				{
					int sum=0;
					for(int i=0; i<7; ++i)
						sum+=(s>>i&1?a[i]:-a[i]);
//					printf("Delete(%d)
",sum);
					st[s].erase(st[s].find(sum));
				}
				break;
			}
			case 3: 
			{
				x=read();
				if(!tot) {puts("-1"); break;}
				if(!vis[x]) Div(x);
				int *a=A[x],ans=0;
				printf("A[%d]: ",x); for(int i=0; i<7; ++i) printf("%d ",a[i]); puts("");
				for(int s=0; s<all; ++s)
				{
					int sum=0;
					for(int i=0; i<7; ++i)
						sum+=(s>>i&1?a[i]:-a[i]);
//					std::multiset<int>::iterator it=st[s].upper_bound(sum);
					ans=std::max(ans,std::max(*st[s].rbegin()-sum,sum-*st[s].begin()));
					printf("s:%d sum:%d big:%d ",s,sum,*st[s].rbegin());
					printf("small:%d
",*st[s].begin());
//					ans=std::min(ans,*it-sum);
//					printf("s:%d sum:%d big:%d ",s,sum,*it);
//					ans=std::min(ans,sum-*(--it));
//					printf("small:%d
",*it);
				}
				printf("%d
",ans);
				break;
			}
		}
	}
	return 0;
}/*
12
3
1 20
1 15
3 30
1 30
3 30
2 10
3 27
1 15
2 15
2 20
2 30
3 5
*/
原文地址:https://www.cnblogs.com/SovietPower/p/9900210.html