• 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
    ",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
    ",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;
    }
  • 相关阅读:
    2018/12/21 HDU-2077 汉诺塔IV(递归)
    2018-12-08 acm日常 HDU
    2018/12/12 acm日常 第二周 第六题
    git 添加远程分支,并可以code review.
    zookeeper数据迁移方法
    gem install nokogiri -v '1.6.6.2' 出错
    gem install json -v '1.8.2' error
    gem install bundle 安装失败
    全能型开源远程终端:MobaXterm
    如何写好 Git Commit 信息
  • 原文地址:https://www.cnblogs.com/DUXT/p/6119395.html
Copyright © 2020-2023  润新知