• Codeforces Round #384 Div.2


    A:Vladik and flights

    题目大意:给定一个长度为n的01串和a,b两个位置,如果一个位置和另一个位置上的数相同,那么这两个位置之间相互到达的代价是0,否则代价是这两个位置的距离,问从a到b最少需要多少代价。

    思路:答案非0即1,0的情况就是这两个位置上的数相同,1就代表一定同时存在0和1,那么就把这两个点分别移到0,1交界的位置,那么答案就是1。

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define maxn 100005
    const int inf=1e9;
    
    int n,st,ed,ans;
    char s[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(),st=read(),ed=read();
    	scanf("%s",s+1);
    	puts(s[st]==s[ed]?"0":"1");
    	return 0;
    }
    

    B:Chloe and the sequence

    题目大意:给定一个序列的构造方式,第一个序列是[1],第二个序列是[1,2,1],第三个序列是[1,2,1,3,1,2,1],然后第n个序列就是把第n-1个序列翻折后再在最中间加一个数n,然后问第n个序列中第k个数是多少。

    思路:设len为第n个序列的长度(显然len=(1<<n)-1),mid为最中间数的位置,然后如果k>mid,显然有a[k]=a[len-k+1](满足对称性),然后如果k<mid,那么就可以把序列折半看成是一个子问题,k==mid就输出这是第几个序列就好了。

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    int n;
    long long len,k;
    
    inline long long read(){
    	long long 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(),k=read();
    	len=(1ll<<n)-1;
    	for (int i=n;i;i--){
    		if (k==len/2+1){printf("%d
    ",i);return 0;}
    		if (k>len/2+1) k=len-k+1;
    		len>>=1;
    	}
    	return 0;
    }
    

    C:Vladik and fractions

    题目大意:给定n,找到三个互不相同的整数使得2/n=1/a+1/b+1/c。

    思路:2/n=1/n+1/(n+1)+1/(n*(n+1)),注意互不相同要特判n=1的情况。

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    int n,m;
    
    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();
    	if (n==1){puts("-1");return 0;}
    	else{printf("%d %d %d
    ",n,n+1,n*(n+1));}
    	return 0;
    }
    

    D:Chloe and pleasant prizes

    题目大意:一颗以1为根的树,给定每个点的点权,找到两颗没有交集的子树并使它们的权值和尽量大,如果找不到输出-1。

    思路:首先找不到的情况就是一条链的情况(当然1必须是该链的一个端点),然后答案直接就tree dp就好了,和tree dp求树最长链基本一毛一样。

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define maxn 200005
    const long long inf=1e18;
    
    int n,m,maxdeg,tot;
    long long ans;
    
    int now[maxn],pre[maxn*2],son[maxn*2],deg[maxn];
    long long sum[maxn];
    bool vis[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){
    	son[++tot]=b;
    	pre[tot]=now[a];
    	now[a]=tot;
    }
    
    void link(int a,int b){
    	add(a,b),add(b,a);
    }
    
    long long tree_dp(int x,int fa){
    	long long mx=-inf,tx=-inf;
    	for (int p=now[x];p;p=pre[p])
    		if (son[p]!=fa){
    			long long tmp=tree_dp(son[p],x);
    			if (tmp>mx) tx=mx,mx=tmp;
    			else tx=max(tx,tmp);
    			ans=max(ans,tx+mx);
    			sum[x]+=sum[son[p]];
    		}
    	return max(mx,sum[x]);
    }
    
    void dfs(int x,int fa){
    	vis[x]=1;
    	for (int p=now[x];p;p=pre[p]) if (son[p]!=fa){dfs(son[p],x);break;}
    }
    
    bool check(){
    	dfs(1,0);
    	for (int i=1;i<=n;i++) if (!vis[i]) return 1;
    	return 0;
    }
    
    int main(){
    	n=read(); ans=-inf;
    	for (int i=1;i<=n;i++) sum[i]=read();
    	for (int i=1,a,b;i<n;i++) a=read(),b=read(),link(a,b);
    	if (!check()){puts("Impossible"); return 0;}
    	tree_dp(1,0);
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    E:Vladik and cards

    题目大意:在给定的只由1到8组成的序列中,找到一个子序列,使得其满足以下条件:1.任意一个数字出现的次数之间不能相差超过1,也就是说每个数字要么出现x次,要么出现x+1次。2.如果子序列中第一次出现某个数字,就必须全部出现完,也就是说相同的数字在子序列中一定是一条线段而不能断开。在以上基础上要求子序列长度最长。

    思路:状压dp很显然,关键是二分比较难想,因为一个数字要么出现x次,要么出现x+1次,那么我们就二分这个x(显然具有单调性),然后考虑如何去check就好了。

    因为答案肯定是形如x*y+(8-y)*(x+1),这个y就是有多少个数字出现x次,然后就可以令状态f[i][S]表示当前状态为S,当前位于第i个时的y的值,然后枚举当前选哪个数字转移即可。

    #include<cmath>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define maxn 1005
    #define maxs (1<<8)
    const int inf=1e9;
    
    int n,ans=-inf;
    int a[maxn],cnt[9];
    int f[maxn][maxs];
    
    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;
    }
    
    vector<int> v[9];
    
    void clear(){memset(cnt,0,sizeof(cnt)),memset(f,-1,sizeof(f));}
    
    bool check(int mid){
    	clear();f[1][0]=0;
    	for (int i=1;i<=n;i++){
    		for (int S=0;S<maxs;S++){
    			if (f[i][S]==-1) continue;
    			for (int j=1;j<=8;j++)
    				if (!(S&(1<<(j-1)))){
    					int x=cnt[j]+mid;
    					if (x>v[j].size()) continue;
    					f[v[j][x-1]+1][S|(1<<(j-1))]=max(f[v[j][x-1]+1][S|(1<<(j-1))],f[i][S]);
    					if (++x>v[j].size()) continue;
    					f[v[j][x-1]+1][S|(1<<(j-1))]=max(f[v[j][x-1]+1][S|(1<<(j-1))],f[i][S]+1);
    				}
    		}
    		cnt[a[i]]++;
    	}
    	int tt=-1;
    	for (int i=1;i<=n+1;i++) tt=max(tt,f[i][maxs-1]);
    	return tt==-1?0:(ans=max(ans,tt*(mid+1)+(8-tt)*mid),1);
    }
    
    int main(){
    	n=read();
    	for (int i=1;i<=n;i++) a[i]=read(),v[a[i]].push_back(i);
    	int l=1,r=n;
    	while (l<=r){
    		int mid=(l+r)>>1;
    		if (check(mid)) l=mid+1;
    		else r=mid-1;
    	}
    	if (ans==-inf){
    		ans=0;
    		for (int i=1;i<=8;i++) if (v[i].size()) ans++;
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    

      

  • 相关阅读:
    基于Kubernates微服务案例
    领导人怎样带领好团队
    前端性能核对表Checklist-2018
    国际巨头互联网公司一些运营与管理思路
    IT研发工程师职业规划
    高性能风控数据平台设计
    基础设施DevOps演进之路
    2017-2018年Scrum状态调查报告
    大型互联网系统的监控流水线
    小程序【情书与歌】一小时过审经验小谈
  • 原文地址:https://www.cnblogs.com/DUXT/p/6187900.html
Copyright © 2020-2023  润新知