zoukankan      html  css  js  c++  java
  • NOIP2016题解

    D1T1:把方向和朝向异或一下,在mod n意义下+1s或-1s。

    #include<cstdio>
    const int N=1e5+5;
    int n,m,j,k,v,s[N];
    char t[N][11];
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=0;i<n;++i)
    		scanf("%d%s",s+i,t[i]);
    	while(m--){
    		scanf("%d%d",&j,&k);
    		(v+=j^s[v]?k:n-k)%=n;
    	}
    	puts(t[v]);
    }
    

    D1T2:设i的深度为d[i],点i的答案是满足s[j]在其子树中,d[s[j]]==d[i]+w[i],且lca[j]在其子树外或等于i的j的个数,加上t[j]在其子树中,d[lca[j]]*2-d[s[j]]==d[i]-w[i],且lca[j]在其子树外(s[j]在子树外)的j的个数。考虑差分链,++a[s[i]],--a[lca[j]的父亲],++b[t[j]],--b[lca[j]],那么查询子树中对应的a的和和b的和就是答案。通过dfs序,转化为查询区间中等于一个数的数的权和,那么差分询问,设查询[l,r],答案就是r处的答案减去l-1处的答案。

    #include<cstdio>
    const int N=3e5+5;
    struct edge{
    	int v;edge*s;
    }e[N*2];
    edge*o=e,*h[N];
    void ins(int u,int v){
    	edge s={v,h[u]};
    	*(h[u]=o++)=s;
    }
    typedef int arr[N];
    arr d,p,r,c,y,l,q,z[4];
    void dfs1(int u){
    	r[u]=1;
    	for(edge*i=h[u];i;i=i->s)
    		if(i->v^p[u]){
    			d[i->v]=d[p[i->v]=u]+1;
    			dfs1(i->v);
    			r[u]+=r[i->v];
    			if(r[c[u]]<r[i->v])
    				c[u]=i->v;
    		}
    }
    void dfs2(int u,int f){
    	static int n2;
    	l[u]=++n2,y[u]=f;
    	if(c[u])dfs2(c[u],y[u]);
    	for(edge*i=h[u];i;i=i->s)
    		if(i->v^p[u]&&i->v^c[u])
    			dfs2(i->v,i->v);
    }
    int lca(int s,int t){
    	while(y[s]^y[t]){
    		if(d[y[s]]<d[y[t]])
    			s^=t,t^=s,s^=t;
    		s=p[y[s]];
    	}
    	return d[s]<d[t]?s:t;
    }
    struct foo{
    	int z,x,y;foo*s;
    }e2[N*4];
    foo*o2=e2,*h2[N],*h3[N];
    #define ins2(v,...){
    	foo e={__VA_ARGS__,v};
    	*(v=o2++)=e;
    }
    struct bar{
    	int x,y;bar*s;
    }e3[N*4];
    bar*o3=e3,*h4[N],*h5[N];
    #define ins3(v,...){
    	bar e={__VA_ARGS__,v};
    	*(v=o3++)=e;
    }
    int n,m,s,t;
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<n;++i){
    		scanf("%d%d",&s,&t);
    		ins(s,t),ins(t,s);
    	}
    	dfs1(1),dfs2(1,1);
    	for(int i=1;i<=n;++i){
    		scanf("%d",&s);
    		int x=l[i]-1,y=x+r[i];
    		ins2(h2[x],i,d[i]+s,-1);
    		ins2(h2[y],i,d[i]+s,+1);
    		ins2(h3[x],i,d[i]-s,-1);
    		ins2(h3[y],i,d[i]-s,+1);
    	}
    	while(m--){
    		scanf("%d%d",&s,&t);
    		int i=lca(s,t),j=p[i];
    		int x=d[s],y=d[i]*2-x;
    		ins3(h4[l[s]],x,+1);
    		ins3(h4[l[j]],x,-1);
    		ins3(h5[l[t]],y,+1);
    		ins3(h5[l[i]],y,-1);
    	}
    	for(int i=1;i<=n;++i){
    		for(bar*j=h4[i];j;j=j->s)
    			z[0][j->x]+=j->y;
    		for(bar*j=h5[i];j;j=j->s)
    			z[3][j->x]+=j->y;
    		for(foo*j=h2[i];j;j=j->s)
    			q[j->z]+=z[0][j->x]*j->y;
    		for(foo*j=h3[i];j;j=j->s)
    			q[j->z]+=z[3][j->x]*j->y;
    	}
    	for(int i=1;i<=n;++i)
    		printf("%d ",q[i]);
    }
    

    D1T3:设f[i][j][2]表示前i节课,申请了j次,第i节课有没有申请的期望。floyd预处理两点间最短路。讨论所有情况,按概率加权直接转移。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using std::min;
    const int N=2005;
    int n,m,v,e,a,b,w;
    int c[N],d[N],z[305][305];
    double p[N],f[N][N][2];
    template<class T>
    void eq1(T&a,T b){a=b<a?b:a;}
    int main(){
    	scanf("%d%d%d%d",&n,&m,&v,&e);
    	for(int i=1;i<=n;++i)
    		scanf("%d",c+i);
    	for(int i=1;i<=n;++i)
    		scanf("%d",d+i);
    	for(int i=1;i<=n;++i)
    		scanf("%lf",p+i);
    	memset(z,63,sizeof z);
    	for(int i=1;i<=v;++i)
    		z[i][i]=0;
    	while(e--){
    		scanf("%d%d%d",&a,&b,&w);
    		eq1(z[a][b],w);
    		eq1(z[b][a],w);
    	}
    	for(int k=1;k<=v;++k)
    		for(int i=1;i<=v;++i)
    			for(int j=1;j<=v;++j)
    				eq1(z[i][j],z[i][k]+z[k][j]);
    	for(int i=1;i<=n;++i)
    		for(int j=0;j<=m;++j)
    			f[i][j][0]=f[i][j][1]=1e18;
    	f[1][0][0]=f[1][1][1]=0;
    	for(int i=2;i<=n;++i){
    		f[i][0][0]=f[i-1][0][0]+z[c[i-1]][c[i]];
    		for(int j=1;j<=i;++j){
    			f[i][j][0]=min(f[i-1][j][0]+z[c[i-1]][c[i]],f[i-1][j][1]+z[c[i-1]][c[i]]*(1-p[i-1])+z[d[i-1]][c[i]]*p[i-1]);
    			f[i][j][1]=min(f[i-1][j-1][0]+z[c[i-1]][c[i]]*(1-p[i])+z[c[i-1]][d[i]]*p[i],f[i-1][j-1][1]+z[c[i-1]][c[i]]*(1-p[i-1])*(1-p[i])+z[d[i-1]][c[i]]*p[i-1]*(1-p[i])+z[c[i-1]][d[i]]*(1-p[i-1])*p[i]+z[d[i-1]][d[i]]*p[i-1]*p[i]);
    		}
    	}
    	double ans=1e18;
    	for(int j=0;j<=m;++j)
    		eq1(ans,min(f[n][j][0],f[n][j][1]));
    	printf("%.2f
    ",ans);
    }
    

    D2T1:预处理$[inom{i}{j}equiv0pmod{k}]$的二维前缀和。

    #include<cstdio>
    const int N=2005;
    int t,p,n,m;
    int c[N][N],s[N][N];
    int main(){
    	scanf("%d%d",&t,&p);
    	for(int i=0;i<N;++i){
    		c[i][0]=1;
    		for(int j=1;j<=i;++j)
    			c[i][j]=(c[i-1][j]+c[i-1][j-1])%p;
    	}
    	for(int i=1;i<N;++i)
    		for(int j=1;j<N;++j){
    			s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
    			if(j<=i)s[i][j]+=!c[i][j];
    		}
    	while(t--){
    		scanf("%d%d",&n,&m);
    		printf("%d
    ",s[n][m]);
    	}
    }
    

    D2T2:先从大到小排序,若q=0,考虑每次把分成的两个数压进两个队列,那么压进去的数一定不大于上次压进对应队列的数。容易验证若q!=0仍然成立。

    #include<algorithm>
    #include<cstdio>
    #include<functional>
    using namespace std;
    const int M=7e6+5;
    int q1[M],q2[M],q3[M];
    int m,q,u,v,t;
    int a1,b1,a2,b2,a3,b3;
    inline int pop(){
    	return a1!=b1&&(a2==b2||q1[a1]>=q2[a2])&&(a3==b3||q1[a1]>=q3[a3])?q1[a1++]:a2!=b2&&(a1==b1||q2[a2]>=q1[a1])&&(a3==b3||q2[a2]>=q3[a3])?q2[a2++]:q3[a3++];
    }
    int main(){
    	scanf("%d%d%d%d%d%d",&b1,&m,&q,&u,&v,&t);
    	for(int i=0;i<b1;++i)
    		scanf("%d",q1+i);
    	sort(q1,q1+b1,greater<int>());
    	for(int i=1;i<=m;++i){
    		int j=pop()+(i-1)*q;
    		int k=1ll*j*u/v;
    		q2[b2++]=max(k,j-k)-i*q;
    		q3[b3++]=min(k,j-k)-i*q;
    		if(i%t==0)
    			printf(i==t?"%d":" %d",j);
    	}
    	puts("");
    	for(int i=1;i<=b1+m;++i){
    		int j=pop()+m*q;
    		if(i%t==0)
    			printf(i==t?"%d":" %d",j);
    	}
    }
    

    D2T3:先枚举两只猪,算出对应抛物线能打掉哪些猪。f[S]表示状态为S的最小步数,显然可以O(n^2)转移。考虑到每只猪都要打掉,因此只用考虑某一只没被打掉的猪和其他猪一起被打掉的情况,就可以O(n)转移了。

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<utility>
    #define x first
    #define y second
    using std::pair;
    typedef double real;
    typedef pair<real,real>vec;
    const real eps=1e-8;
    int in(vec a,vec l){
    	return fabs(l.x*a.x*a.x+l.y*a.x-a.y)<eps;
    }
    const int N=18;
    vec a[N];
    void eq1(int&a,int b){
    	a=b<a?b:a;
    }
    int q,n,e[N][N],f[1<<N];
    int main(){
    	scanf("%d",&q);
    	while(q--){
    		memset(e,0,sizeof e);
    		scanf("%d%*d",&n);
    		for(int i=0;i<n;++i)
    			scanf("%lf%lf",&a[i].x,&a[i].y);
    		for(int i=0;i<n;++i){
    			e[i][i]=1<<i;
    			for(int j=i+1;j<n;++j){
    				vec s=a[i],t=a[j];
    				real a1=s.x*s.x,b1=s.x,c1=s.y;
    				real a2=t.x*t.x,b2=t.x,c2=t.y;
    				real d=a1*b2-a2*b1;
    				if(fabs(d)>eps){
    					real x=(c1*b2-c2*b1)/d;
    					if(x<-eps){
    						vec l(x,(a1*c2-a2*c1)/d);
    						for(int k=0;k<n;++k)
    							e[i][j]|=in(a[k],l)<<k;
    					}
    				}
    			}
    		}
    		for(int i=1;i<1<<n;++i)
    			f[i]=n;
    		for(int i=0;i<1<<n;++i){
    			int j=__builtin_ctz(~i);
    			for(int k=j;k<n;++k)
    				eq1(f[i|e[j][k]],f[i]+1);
    		}
    		printf("%d
    ",f[(1<<n)-1]);
    	}
    }
    
  • 相关阅读:
    VS2012 Unit Test(Void, Action, Func) —— 对无返回值、使用Action或Func作为参数、多重载的方法进行单元测试
    string中Insert与Format效率对比、String与List中Contains与IndexOf的效率对比
    VS2012 Unit Test —— 我对接口进行单元测试使用的技巧
    委托又给我惹麻烦了————记委托链的取消注册、获取返回值
    委托的N种写法,你喜欢哪种?
    VS2012 单元测试之泛型类(Generics Unit Test)
    Unity V3 初步使用 —— 为我的.NET项目从简单三层架构转到IOC做准备
    使用NuGet助您玩转代码生成数据————Entity Framework 之 Code First
    JqueryEasyUI浅谈---视频教程公布
    JqueryEasyUI浅谈本地化应用
  • 原文地址:https://www.cnblogs.com/f321dd/p/6100161.html
Copyright © 2011-2022 走看看