NOIP 2015 D2 T1T2T3【写着玩

80 篇文章 0 订阅
16 篇文章 0 订阅

……去年去考D2似乎只有二十分来着……【捂脸

于是今天晚上就补补进度【

T1:二分答案【去年不会于是写的贪心【跪地

#include<bits/stdc++.h>
#define MAXN 50005
using namespace std;	int l,n,m;
int a[MAXN];

bool check(int x){
	for(int pre = 0,cnt = 0,i = 1;i<=n;++i){
		if(a[i] - a[i-1] + pre < x)	++cnt , pre = a[i] - a[i-1] + pre;
		else	pre = 0;
		if(cnt>m)	return 0;
	}
	return 1;
}

int main(){
	scanf("%d%d%d",&l,&n,&m);
	a[++n] = l;
	for(int i=1;i<n;++i)	scanf("%d",a+i);
	int L = 0 , R = l;
	while(L^R){
		int mid = ((L+R)>>1)+1;
		if(check(mid))	L = mid;
		else	R = mid-1;
	}
	printf("%d",L);
	return 0;
}

T2:O(n*m*k)的dp,滚动一下优化空间,f[i][j][k][0..1]表示a串匹配到第i个字符,b串匹配到第j个字符,已经分了k段,第i个字符选不选(因为在转移到f[i+1][j+1][k][0..1]的时候必须连续才合法)【对不起代码写的丑23333强行增加代码长度

#include<bits/stdc++.h>
#define MAXN 1005
#define MAXM 205
#define MAXK 205
#define MOD 1000000007
using namespace std;	int n,m,K;
int f[2][MAXM][MAXK][2];
char a[MAXN],b[MAXM];

int main(){
	scanf("%d%d%d%s%s",&n,&m,&K,a+1,b+1);
	
//	f[0][0][0][0] = f[0][0][0][1] = f[1][0][0][0] = f[1][0][0][1] = 1;
	f[0][0][0][1] = f[1][0][0][1] = 1;
	for(int now=1,i=1;now<=n;i=(++now)&1){
		for(int j=1;j<=min(now,m);++j){
			for(int k=1;k<=K;++k){
				if(a[now]==b[j]){
					(f[i][j][k][1] += f[i^1][j-1][k][1]) %= MOD;
					(f[i][j][k][1] += f[i^1][j-1][k-1][0]) %= MOD;
					(f[i][j][k][1] += f[i^1][j-1][k-1][1]) %= MOD;
					
					(f[i][j][k][0] += f[i^1][j][k][1]) %= MOD;
					(f[i][j][k][0] += f[i^1][j][k][0]) %= MOD;
				}
				else{
					(f[i][j][k][0] += f[i^1][j][k][0]) %= MOD;
					(f[i][j][k][0] += f[i^1][j][k][1]) %= MOD;
				}
			}
		}
		memset(f[i^1],0,sizeof f[i^1]);
//		f[i^1][0][0][0] = f[i^1][0][0][1] = 1;
		f[i^1][0][0][1] = 1;
	}
	printf("%d",(f[n&1][m][K][0]+f[n&1][m][K][1])%MOD);
	return 0;
}

T3:……听说可以O(n)【因为删除的路径肯定在最长链上,于是就变成了一条链上挂着树,瞎搞搞扫过去】我等蒟蒻还是默默地带log吧23333

       先预处理每个询问的LCA,最长的最短肯定二分答案,在记录的时候直接在两个端点和LCA上打标机,最后按照dfs序倒着更新,显然可以O(n)找到所有链的交,如果交集为空显然不合法,再check删掉交集里最长的边是否合法,好写好调【无视一些没有使用的数组嘛2333

#include<bits/stdc++.h>
#define MAXN 300005
using namespace std;	int n,m;
//=================================================
inline int read(){
	char ch = getchar();
	while(!isdigit(ch))	ch = getchar();
	int rtn = 0;
	while(isdigit(ch))	rtn = rtn*10 +ch-'0' , ch = getchar();
	return rtn;
}
//=================================================
int root = 20000218;
struct t1{
	int to,nxt,lth;
}edge[MAXN<<1];	int cnt_edge = 0;
int fst[MAXN];
void addedge(int x,int y,int l){
	edge[++cnt_edge].to = y;
	edge[cnt_edge].nxt = fst[x];
	edge[cnt_edge].lth = l;
	fst[x] = cnt_edge;
	
	edge[++cnt_edge].to = x;
	edge[cnt_edge].nxt = fst[y];
	edge[cnt_edge].lth = l;
	fst[y] = cnt_edge;
}
int dfn[MAXN],idf[MAXN],cnt_dfs;
int fth[MAXN],dpt[MAXN],dis[MAXN];
int siz[MAXN],top[MAXN],son[MAXN];

int dd[MAXN];

void dfs1(int now){
	siz[now] = 1;
	for(int tmp = fst[now];tmp;tmp=edge[tmp].nxt){
		int aim = edge[tmp].to;
		if(aim==fth[now])	continue;
		fth[aim] = now;
		dpt[aim] = dpt[now]+1;
		dis[aim] = dis[now] + edge[tmp].lth;
		dd[aim] = edge[tmp].lth;
		dfs1(aim);
		siz[now] += siz[aim];
		if(siz[aim] > siz[son[now]])	son[now] = aim;
	}
}

void dfs2(int now,int tp){
	top[now] = tp;
	dfn[now] = ++cnt_dfs;
	idf[cnt_dfs] = now;
	if(son[now])	dfs2(son[now],tp);
	for(int tmp = fst[now];tmp;tmp=edge[tmp].nxt){
		int aim = edge[tmp].to;
		if(aim==fth[now]||aim==son[now])	continue;
		dfs2(aim,aim);
	}
}

struct t2{
	int lth,lca;
	int u,v;
	bool operator < (const t2 &ano) const{
		return lth < ano.lth;
	}
}Q[MAXN];

int LCA(int x,int y){
	while(top[x]^top[y]){
		if(dpt[fth[top[x]]] < dpt[fth[top[y]]])	swap(x,y);
		x = fth[top[x]];
	}
	return dpt[x]<dpt[y]?x:y;
}

int tag[MAXN];

inline bool sol(int x){
	memset(tag,0,sizeof tag);
	
	int cnt = 0 , LONG = 0;
	
	for(int i=1;i<=m;++i)
		if(Q[i].lth>x)
			++tag[Q[i].u] , ++tag[Q[i].v] , tag[Q[i].lca]-=2 , ++cnt , LONG = max(LONG,Q[i].lth);
	
	if(!cnt)	return 1;
			
	int mx = -1;
	
	for(int i=n;i;--i){
		int x = idf[i];
		tag[fth[x]] += tag[x];
		if(tag[x]==cnt)	mx = max(mx,dd[x]);
	}
	
	if(!~mx)	return 0;
	if(LONG - mx > x)	return 0;
	return 1;
}

inline void work(){
	int L = 0 , R = n*1000;
	while(L^R){
		int mid = (L+R)>>1;
		if(sol(mid))	R = mid;
		else	L = mid+1;
	}
	printf("%d\n",L);
}

int read_x,read_y,read_l;
int main(){
	n = read() , m = read();
	(root%=n)++;
	
	for(int i=1;i<n;++i){
		read_x = read() , read_y = read() , read_l = read();
		addedge(read_x,read_y,read_l);
	}
	
	dpt[root] = 1;
	dfs1(root);dfs2(root,root);
	
	for(int i=1;i<=m;++i){
		Q[i].u = read() , Q[i].v = read();
		Q[i].lca = LCA(Q[i].u,Q[i].v);
		Q[i].lth = dis[Q[i].u] + dis[Q[i].v] - (dis[Q[i].lca]<<1);
	}
	
	work();
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值