Codeforces Round #381 Div.2

A:Alyona and copybooks

题目大意:已经给了你n本书,你可以选择花a元买一本书,花b元买两本书(严格两本),花c元买三本书(严格三本),让你花最少的钱买x本书使得n+x为4的倍数。

思路:枚举一下买一本书,两本书,三本书的次数,然后统计答案即可。

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define inf 1e18

int n,a,b,c;

inline int read(){
	int x=0,f=1;char ch=getchar();
	for (;ch<'0'||ch>'9';ch=getchar())if (ch=='-') f=-1;
	for (;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x*f;
}

inline void print(int x){
	if (x>=10) print(x/10);
	putchar(x%10+'0');
}

int main(){
	n=read(),a=read(),b=read(),c=read();
	long long ans=inf;
	for (int i=0;i<=3;i++)
		for (int j=0;j<=3;j++)
			for (int k=0;k<=3;k++)
				if ((i+j*2+k*3+n)%4==0) ans=min(ans,1ll*a*i+1ll*b*j+1ll*c*k);
	printf("%lld\n",ans);
	return 0;
}

B:Alyona and flowers

题目大意:给你n个数,m个区间,然后对于所有的区间可以选也可以不选,每个区间对答案的贡献为这个区间的权值之和,问怎样选择能使答案尽量大。

思路:统计一下每个区间的答案,显然大于0就要加到答案里来。

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define maxn 105

int n,m,ans;
int sum[maxn];

inline int read(){
	int x=0,f=1;char ch=getchar();
	for (;ch<'0'||ch>'9';ch=getchar())if (ch=='-') f=-1;
	for (;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x*f;
}

inline void print(int x){
	if (x>=10) print(x/10);
	putchar(x%10+'0');
}

int main(){
	n=read(),m=read();
	for (int i=1;i<=n;i++) sum[i]=sum[i-1]+read();
	for (int i=1;i<=m;i++){
		int l=read(),r=read();
		ans+=max(0,sum[r]-sum[l-1]);
	}
	printf("%d\n",ans);
	return 0;
}

C:Alyona and mex

题目大意:给出n和m,和m个区间,让你求出一个长度为n的一个数组,让所有区间的mex的最小值尽量大,同时也要给出这个最大的mex值。

对一个集合S求mex即求出不属于集合S的最小非负整数。

思路:首先答案不可能会超过最短区间的长度(这个根据mex的定义可以得出),然后设最短区间长度为len,那么可以构造出一种方案,使得对于任意的区间[i,i+len-1](i∈[1,n]&&i+len-1∈[1,n]),它们的mex值均为len,这样构造的方案也一定合法,因为更长的区间答案也一定是len(可以看作更长的区间由一个长度为len的区间和另外一个区间组成),那么这样显然第一问的答案就是len,因为更大的答案是不可能的,而我们恰巧能构造出答案为len的数组。

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define maxn 100005
#define inf 1e9

int n,m,ans=inf;
int a[maxn];

inline int read(){
	int x=0,f=1;char ch=getchar();
	for (;ch<'0'||ch>'9';ch=getchar())if (ch=='-') f=-1;
	for (;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x*f;
}

inline void print(int x){
	if (x>=10) print(x/10);
	putchar(x%10+'0');
}

int main(){
	n=read(),m=read();
	for (int i=1,l,r;i<=m;i++) l=read(),r=read(),ans=min(ans,r-l+1);
	for (int i=1;i<=ans;i++) a[i]=i-1;
	for (int i=ans+1;i<=n;i++) a[i]=a[i-ans];
	print(ans);puts("");
	for (int i=1;i<=n;i++) print(a[i]),putchar(' ');
	puts("");
	return 0;
}

D:Alyona and a tree

题目大意:给出一个n个点以1为根的树,每个点有一个点权(记为wi),同时每条边有条边权,然后定义dist(i,j)表示点i和点j的距离,然后对于一个点i,要求出在以它为根的子树中有多少个点j满足dist(i,j)<=wj。

思路:单独考虑每一个点对答案的贡献,显然这个点只能对其祖先结点产生贡献,又因为该点到其越远的祖先的dist越大,满足单调性,然后用个倍增找到它最远能对哪个祖先产生贡献,然后打个标记差分一下即可。

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define maxn 200005

int n,m,tot;
int w[maxn],son[maxn*2],pre[maxn*2],val[maxn*2],now[maxn];
long long dis[maxn];
int dep[maxn],f[maxn][22],ans[maxn];

inline int read(){
	int x=0,f=1;char ch=getchar();
	for (;ch<'0'||ch>'9';ch=getchar())if (ch=='-') f=-1;
	for (;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x*f;
}

inline void print(int x){
	if (x>=10) print(x/10);
	putchar(x%10+'0');
}

void add(int a,int b,int c){
	son[++tot]=b;
	pre[tot]=now[a];
	now[a]=tot;
	val[tot]=c;
}

void link(int a,int b,int c){
	add(a,b,c),add(b,a,c);
}

void dfs(int x,int fa){
	dep[x]=dep[fa]+1;
	for (int p=now[x];p;p=pre[p])
		if (son[p]!=fa) f[son[p]][0]=x,dis[son[p]]=dis[x]+val[p],dfs(son[p],x);
}

void getsum(int x,int fa){
	for (int p=now[x];p;p=pre[p]) if (son[p]!=fa) getsum(son[p],x),ans[x]+=ans[son[p]];
}

int main(){
	n=read();int l=log2(n);
	for (int i=1;i<=n;i++) w[i]=read();
	for (int i=1;i<n;i++){
		int a=read(),b=read();
		link(i+1,a,b);
	}
	dfs(1,0);
	for (int i=1;i<=l;i++)
		for (int x=1;x<=n;x++)
			f[x][i]=f[f[x][i-1]][i-1];
	for (int i=1;i<=n;i++){
		int t=log2(dep[i]),a=i;
		for (;dis[i]-dis[f[a][0]]<=w[i]&&f[a][0];){
			for (;!f[a][t]||dis[i]-dis[f[a][t]]>w[i];t--);
			a=f[a][t];
		}
		ans[f[i][0]]++,ans[f[a][0]]--;
	}
	getsum(1,0);
	for (int i=1;i<=n;i++) print(ans[i]),putchar(' ');puts("");
	return 0;
}

E:Alyona and towers

题目大意:给出一个序列,然后每个有m次操作,每次将一段区间的数加上一个数,然后每次操作后询问当前序列中最长的区间[l,r]且满足a[l]<a[l+1]<a[l+2]<...<a[mid-1]<a[mid]>a[mid+1]>...>a[r-2]>a[r-1]>a[r]

思路:之前想法是用线段树维护,记lmax,rmax,ans去搞,然后发现没法知道每次操作后某一个点的值(更新lmax,rmax要用),然后就GG了。。。

然后正解也是维护lmax,rmax,ans,不过不是搞原序列,而是搞出差分序列,即用线段树维护a',其中a'[i]=a[i+1]-a[i]。

这样每次修改只需要把a[l-1]+=val,a[r]-=val即可,那么就可以快速维护lmax,rmax,ans然后用线段树维护即可。

#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define maxn 300005

int n,m;
long long a[maxn];

inline int read(){
	int x=0,f=1;char ch=getchar();
	for (;ch<'0'||ch>'9';ch=getchar())if (ch=='-') f=-1;
	for (;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x*f;
}

inline void print(int x){
	if (x>=10) print(x/10);
	putchar(x%10+'0');
}

struct segment_tree{
	struct treenode{
		int size,lmax,rmax,ans;
	}tree[4*maxn];
	void update(int p,int x){
		tree[p].lmax=tree[p<<1].lmax,tree[p].rmax=tree[p<<1|1].rmax;
		tree[p].ans=max(tree[p<<1].ans,tree[p<<1|1].ans);
		if (!a[x]||!a[x+1]||(a[x]<0&&a[x+1]>0)) return;
		if (tree[p].lmax==tree[p<<1].size) tree[p].lmax+=tree[p<<1|1].lmax;
		if (tree[p].rmax==tree[p<<1|1].size) tree[p].rmax+=tree[p<<1].rmax;
		tree[p].ans=max(tree[p].ans,tree[p<<1].rmax+tree[p<<1|1].lmax);
	}
	void build(int p,int l,int r){
		tree[p].size=r-l+1;
		if (l==r){
			tree[p].lmax=tree[p].rmax=tree[p].ans=1;
			return;
		}
		int mid=(l+r)>>1;
		build(p<<1,l,mid),build(p<<1|1,mid+1,r);
		update(p,mid);
	}
	void change(int p,int l,int r,int pos,int val){
		if (l==r){
			a[l]+=val;
			return;
		}
		int mid=(l+r)>>1;
		if (pos<=mid) change(p<<1,l,mid,pos,val);
		else change(p<<1|1,mid+1,r,pos,val);
		update(p,mid);
	}
}T;

int main(){
	n=read();
	for (int i=1;i<=n;i++) a[i]=read();
	for (int i=1;i<n;i++) a[i]=a[i+1]-a[i];
	n--;
	m=read();
	if (!n){
		for (int i=1;i<=m;i++) puts("1");
		return 0;
	}
	T.build(1,1,n);
	for (int i=1;i<=m;i++){
		int l=read(),r=read(),val=read();
		if (l>1) T.change(1,1,n,l-1,val);
		if (r<=n) T.change(1,1,n,r,-val);
		print(T.tree[1].ans+1),puts("");
	}
	return 0;
}
posted @ 2016-11-30 19:41  DUXT  阅读(312)  评论(0编辑  收藏  举报