NOIP2016 DAY1

T1:听说很简单然后我biubiu了

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define rep(j,k,l) for (int j=k;j<=l;j++)
#define N 100005

using namespace std;
char s[N][15];
int a[N],n,T;

int main(){
	
	scanf("%d%d",&n,&T);
	rep(i,0,n-1) scanf("%d%s",&a[i],s[i]);
	int nw=0;
	while (T--){
		
		int k,l;
		scanf("%d%d",&k,&l);
		k=k^a[nw];
		if (k==0){
			
			nw-=l;
			while (nw<0) nw+=n;
			
		}else{
			
			nw+=l;
			while (nw>=n) nw-=n;  //开始biubiu于等号没写(我听说if比%要快然后就233
			
		}
		
	}
	puts(s[nw]);
	return 0;
	
}



T2:把每一条路拆成朝上走的和朝下走的


发现朝上走的路径上的每一个点=经过的时间和深度的和不变

(每往上一格深度-1时间+1)


发现朝下走的路径上的每一个点=经过的时间和深度的差不变

(每往上一格深度-1时间-1)

问题就变成了一个点子树里标号为一个固定值的点的数量

所以在两条路头加加尾减减一遍dfs求解

易得答案就是刚刚遍历到此点和此点遍历所有子树之后的差(相当于多遍历了他的子树

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define rep(j,k,l) for (int j=k;j<=l;j++)
#define N 300005

using namespace std;
int n,m,cnt,cnp,fa[N],deep[N],st[N],to[2*N],ne[2*N],sz[N],son[N],top[N],ans[N],ck[N];
int To[4*N],Ne[4*N],St[N],Sm[4*N],poi[2*N+5],TO[4*N],NE[4*N],ST[N],SM[4*N],Poi[2*N+5];

void add(int k,int l){
	
	to[++cnt]=l;
	ne[cnt]=st[k];
	st[k]=cnt;
	
}

void dfs1(int k,int ff){
	
	fa[k]=ff;
	deep[k]=deep[ff]+1;
	sz[k]=1;
	int _=0,__=0;
	for (int i=st[k];i;i=ne[i])
		if (to[i]!=ff){
			
			dfs1(to[i],k);
			sz[k]+=sz[to[i]];
			if (sz[to[i]]>__){
				
				__=sz[to[i]];
				_=to[i];
				
			}
			
		}
	son[k]=_;
	
}

void dfs2(int k,bool lych){
	
	if (lych) top[k]=top[fa[k]];
	else top[k]=k;
	if (son[k]) dfs2(son[k],1);
	for (int i=st[k];i;i=ne[i])
		if (to[i]!=fa[k]&&to[i]!=son[k])
			dfs2(to[i],0);
	
}

int lca(int x,int y){
	
	for (;top[x]!=top[y];x=fa[top[x]])
		if (deep[top[x]]<deep[top[y]]) swap(x,y);
	if (deep[x]<deep[y]) swap(x,y);
	return y;
	
}

void ad(int k,int p,int l){
	
	To[++cnt]=p;
	Sm[cnt]=l;
	Ne[cnt]=St[k];
	St[k]=cnt;
	
}

void AD(int k,int p,int l){
	
	TO[++cnp]=p;
	SM[cnp]=l;
	NE[cnp]=ST[k];
	ST[k]=cnp;
	
}

void dfs(int k){
	
	int qs=poi[deep[k]+ck[k]],QS=Poi[deep[k]-ck[k]+N];
	
	for (int i=st[k];i;i=ne[i])
		if (to[i]!=fa[k]) dfs(to[i]);
	
	for (int i=St[k];i;i=Ne[i])
		poi[To[i]]+=max(0,Sm[i]);
	for (int i=ST[k];i;i=NE[i])
		Poi[TO[i]]+=max(0,SM[i]);
	
	ans[k]+=poi[deep[k]+ck[k]]+Poi[deep[k]-ck[k]+N]-qs-QS;
	
	for (int i=St[k];i;i=Ne[i])
		poi[To[i]]+=min(0,Sm[i]);
	for (int i=ST[k];i;i=NE[i])
		Poi[TO[i]]+=min(0,SM[i]);
	
}

int main(){
	
	scanf("%d%d",&n,&m);
	rep(i,1,n-1){
		
		int k,l;
		scanf("%d%d",&k,&l);
		add(k,l);add(l,k);
		
	}
	rep(i,1,n) scanf("%d",&ck[i]);
	dfs1(1,1);dfs2(1,0);
	cnt=0;cnp=0;
	rep(i,1,m){
		
		int k,l;
		scanf("%d%d",&k,&l);
		int p=lca(k,l);
		
		ad(k,deep[k],1);
		ad(p,deep[k],-1); //向上的路径
		AD(l,deep[l]-(deep[l]+deep[k]-2*deep[p])+N,1);
		AD(p,deep[l]-(deep[l]+deep[k]-2*deep[p])+N,-1); //向下的路径
		if (deep[k]==deep[p]+ck[p]) ans[p]--;//,printf("ok\n"); //节点会被记两次要-1
		
	}
	dfs(1);
	rep(i,1,n-1) printf("%d ",ans[i]);
	printf("%d\n",ans[n]);
	
}



T3:学会新技能:眼睛看不调试调程序

f[i][k][j]表示到第i个点申请j个教室 

k=0表示该教室不申请k=1表示该教室申请

转移方程见程序

考场上居然忘了有floyd这种东西n遍spfa神清气爽

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define rep(j,k,l) for (int j=k;j<=l;j++)
#define N 305
#define M 2005
#define K 90005
#define inf 10000000

using namespace std;
int n,m,v,e,a[M],b[M];
double f[M][2][M],rd[N][N],c[M];

void FLOYD(){
	
	rep(k,1,v) rep(i,1,v) rep(j,1,v)
		if (rd[i][k]<inf&&rd[k][j]<inf&&
			rd[i][j]>rd[i][k]+rd[k][j])
		rd[i][j]=rd[i][k]+rd[k][j];
	
}

int main(){
	
	scanf("%d%d%d%d",&n,&m,&v,&e);
	rep(i,1,n) scanf("%d",&a[i]);
	rep(i,1,n) scanf("%d",&b[i]);
	rep(i,1,n) scanf("%lf",&c[i]);
	rep(i,1,v) rep(j,1,v) rd[i][j]=inf;
	rep(i,1,v) rd[i][i]=0;
	rep(i,1,e){
		
		int k,l,p;
		scanf("%d%d%d",&k,&l,&p);
		if (rd[k][l]>p) rd[k][l]=p,rd[l][k]=p;
		
	}
	FLOYD();
	rep(i,1,n) rep(j,0,1) rep(k,0,m) f[i][j][k]=-1;
	f[1][0][0]=0;f[1][1][1]=0;//编号--是否申请--已申请数
	rep(i,1,n-1){
		
		rep(j,0,m){
			
			if (f[i][0][j]>=0){
				
				double cl;
				cl=f[i][0][j]+rd[a[i]][a[i+1]];
				if (f[i+1][0][j]==-1||f[i+1][0][j]>cl)
					f[i+1][0][j]=cl;
				cl=f[i][0][j]+rd[a[i]][a[i+1]]*(1-c[i+1])+rd[a[i]][b[i+1]]*c[i+1];
				if (f[i+1][1][j+1]==-1||f[i+1][1][j+1]>cl)
					f[i+1][1][j+1]=cl;
				
			}
			
			if (f[i][1][j]>=0){
				
				double cl;
				cl=f[i][1][j]+rd[a[i]][a[i+1]]*(1-c[i])+rd[b[i]][a[i+1]]*c[i];
				if (f[i+1][0][j]==-1||f[i+1][0][j]>cl)
					f[i+1][0][j]=cl;
				cl=f[i][1][j]+rd[a[i]][a[i+1]]*(1-c[i])*(1-c[i+1])+rd[a[i]][b[i+1]]*(1-c[i])*c[i+1]+rd[b[i]][a[i+1]]*c[i]*(1-c[i+1])+rd[b[i]][b[i+1]]*c[i]*c[i+1];
				if (f[i+1][1][j+1]==-1||f[i+1][1][j+1]>cl)
					f[i+1][1][j+1]=cl;
				
			}
			
		}
		
	}
	double ans=2000000000;
	rep(i,0,m) rep(j,0,1) if (f[n][j][i]<ans&&f[n][j][i]!=-1) ans=f[n][j][i];
	printf("%.2f\n",ans);
	
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值