NOIP2015

提高组

day1

T1

纯模拟。

T2

Description
给定一个有向图,求最小的环的大小。
Solution
因为每个点的出度都为1,没有自环,所以直接tarjan求每个环的大小即可。

#include<bits/stdc++.h>
using namespace std;

const int N=200005;
struct graph{
	int nxt,to;
}e[N];
int g[N],f[N],dfn[N],low[N],sta[N],n,top,ans,cnt;
bool ins[N];
void tarjan(int u){
    dfn[u]=low[u]=++cnt;
    sta[++top]=u;ins[u]=true;
    for(int i=g[u];i;i=e[i].nxt)
        if(!dfn[e[i].to]){
            tarjan(e[i].to);
            low[u]=min(low[u],low[e[i].to]);
        }
        else if(ins[e[i].to])
            low[u]=min(low[u],low[e[i].to]);
    if(dfn[u]==low[u]){
    	int tmp=0;
        while(sta[top+1]!=u){
        	++tmp;
            f[sta[top]]=u;
            ins[sta[top--]]=false;
        }
        if(tmp>1) ans=min(ans,tmp);
    }
}
void adde(int x,int y){
	e[++cnt].nxt=g[x];g[x]=cnt;e[cnt].to=y;
}
int main(){
	scanf("%d",&n);
	for(int i=1,x;i<=n;++i){
		scanf("%d",&x);
		adde(i,x);
	}
	ans=n;cnt=0;
    for(int i=1;i<=n;i++)
        if(!dfn[i]) tarjan(i);
    printf("%d",ans);
	return 0;
}

day2

T1

Description
从一个数组中删去至多m个数,使\(min\{a_i-a_{i-1}\}\)最大。
Solution
二分答案,贪心判定。

#include<bits/stdc++.h>
using namespace std;

const int N=50005;
int d[N],n,m,l;
bool chk(int ans){
	int cnt=0,lst_d=0;
	for(int i=1;i<=n;++i){
		if(d[i]-lst_d<ans) ++cnt;
		else lst_d=d[i];
	}
	return cnt<=m;
}
int main(){
	scanf("%d%d%d",&l,&n,&m);
	for(int i=1;i<=n;++i)
		scanf("%d",&d[i]);
	d[++n]=l;
	int lef=0,rig=l,mid;
	while(lef<rig){
		mid=(lef+rig+1)>>1;
		if(chk(mid)) lef=mid;
		else rig=mid-1;
	}
	printf("%d",lef);
	return 0;
}

T2

Solution

T3

Solution

普及组

T3

条件1等价于x+z=2y,即x,z同奇偶。
问题转化成给定一个大小为\(n_c\)的集,求\(\sum_{x}\sum_{z,x<z}(x+z)\times(number_x+number_z)\).

\(\begin{aligned}&\sum_{x}\sum_{z,x<z}(x+z)\times(number_x+number_z)\\=&\sum_{x}\sum_{z,x<z}(x\times number_x+z\times number_z+x\times number_z+z\times number_x)\\=&\sum_{x}(n_c-1)(x\times number_x)+\sum_{x}\sum_{z,x\neq z}x\times number_z\\=&\sum_{x}(n_c-1)(x\times number_x)+\sum_{x}x\times \sum_{z,x\neq z}number_z\end{aligned}\)

预处理后扫一遍可求得。

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N=100005,K=10007;
int c[N],num[N],n,m;
int c1[N],c2[N];
ll ans,t1[N],t2[N];
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)
		scanf("%d",&num[i]);
	for(int i=1;i<=n;++i)
		scanf("%d",&c[i]);
	for(int i=1;i<=n;++i)
		if(i&1){
			++c1[c[i]];
			t1[c[i]]+=num[i];
		}
		else{
			++c2[c[i]];
			t2[c[i]]+=num[i];
		}
	
	for(int i=1;i<=m;++i){
		c1[i]%=K;c2[i]%=K;
	}
	
	for(int i=1;i<=n;++i)
		if(i&1){
			ans+=1ll*i*num[i]%K*(c1[c[i]]-1)%K;
			ans%=K;
		}
		else{
			ans+=1ll*i*num[i]%K*(c2[c[i]]-1)%K;
			ans%=K;
		}
	for(int i=1;i<=n;++i)
		if(i&1){
			ans+=1ll*i*(t1[c[i]]-num[i])%K;
			ans%=K;
		}
		else{
			ans+=1ll*i*(t2[c[i]]-num[i])%K;
			ans%=K;
		}
	printf("%lld\n",ans);
	return 0;
} 

T4

用线段树贪心即可。

#include<bits/stdc++.h>
using namespace std;

const int N=100005,M=400005;
struct segmentTree{
	int ma,mw,ia,iw;
}lt[M]; 
int a[N],s[N],n,max_s,ans;
void build(int u,int l,int r){
	if(l==r){
		lt[u].ma=a[l];
		lt[u].mw=a[l]+s[l]*2;
		lt[u].ia=lt[u].iw=l;
		return;
	}
	int mid=(l+r)>>1;
	build(u<<1,l,mid);
	build(u<<1|1,mid+1,r);
	if(lt[u<<1].ma>lt[u<<1|1].ma){
		lt[u].ma=lt[u<<1].ma;
		lt[u].ia=lt[u<<1].ia;
	}
	else{
		lt[u].ma=lt[u<<1|1].ma;
		lt[u].ia=lt[u<<1|1].ia;
	}
	if(lt[u<<1].mw>lt[u<<1|1].mw){
		lt[u].mw=lt[u<<1].mw;
		lt[u].iw=lt[u<<1].iw;
	}
	else{
		lt[u].mw=lt[u<<1|1].mw;
		lt[u].iw=lt[u<<1|1].iw;
	}
}
int ask(int u,int l,int r,int &i){
	if(l==r){
		i=l;
		if(s[l]<=max_s) return lt[u].ma;
		return lt[u].mw-max_s*2;
	}
	if(s[l]>=max_s){
		i=lt[u].iw;
		return lt[u].mw-max_s*2;
	}
	if(s[r]<=max_s){
		i=lt[u].ia;
		return lt[u].ma;
	}
	int mid=(l+r)>>1;
	if(s[mid+1]>=max_s){
		int ret_l=ask(u<<1,l,mid,i);
		int ret_r=lt[u<<1|1].mw-max_s*2;
		if(ret_l>ret_r) return ret_l;
		i=lt[u<<1|1].iw;
		return ret_r;
	}
	int ret_l=lt[u<<1].ma;
	int ret_r=ask(u<<1|1,mid+1,r,i);
	if(ret_l>ret_r){
		i=lt[u<<1].ia;
		return ret_l;
	}
	return ret_r;

}
void remove(int u,int l,int r,int i){
	if(l==r){
		lt[u].ma=0;lt[u].mw=0;
		return;
	}
	int mid=(l+r)>>1;
	if(i<=mid) remove(u<<1,l,mid,i);
	else remove(u<<1|1,mid+1,r,i);
	
	if(lt[u<<1].ma>lt[u<<1|1].ma){
		lt[u].ma=lt[u<<1].ma;
		lt[u].ia=lt[u<<1].ia;
	}
	else{
		lt[u].ma=lt[u<<1|1].ma;
		lt[u].ia=lt[u<<1|1].ia;
	}
	if(lt[u<<1].mw>lt[u<<1|1].mw){
		lt[u].mw=lt[u<<1].mw;
		lt[u].iw=lt[u<<1].iw;
	}
	else{
		lt[u].mw=lt[u<<1|1].mw;
		lt[u].iw=lt[u<<1|1].iw;
	}
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i)
		scanf("%d",&s[i]);
	for(int i=1;i<=n;++i)
		scanf("%d",&a[i]);
	build(1,1,n);
	int ans_i;
	for(int i=1;i<=n;++i){
		ans+=ask(1,1,n,ans_i);
		max_s=max(max_s,s[ans_i]);
		remove(1,1,n,ans_i);
		printf("%d\n",ans);
	}
	return 0;
} 
原文地址:https://www.cnblogs.com/AireenYe/p/15790674.html