Codeforces Round #513 by Barcelona Bootcamp (rated, Div. 1 + Div. 2)

传送门:http://codeforces.com/contest/1060

目录

A.Phone Numbers

题目

题解

代码

B. Maximum Sum of Digits

题目

题解

代码

C. Maximum Subrectangle

题目

题解

代码

D. Social Circles

题目

题解

代码

E. Sergey and Subway

题目

题解

代码


A.Phone Numbers

题目

  给定n个数,要求组成若干个8开头的11位数的号码,一个数字最多只能用一次,问最多能组成多少个。

题解

  令cnt = 8的个数,则ans = min(cnt,n/11)

代码

string s;
int n,k,ans;

int main()
{
	cin>>n>>s;
	for(int i=0;i<n;i++) {
		if(s[i]=='8')	k++;	
	}
	ans = n/11;
	if(k<ans)	ans = k;
	cout<<ans<<endl;	
	return 0;
}

B. Maximum Sum of Digits

题目

  设S(12) = 1+2 = 3, S(0) = 0,现在给定一个n,要求把n拆成a+b,使得 S(a) + S(b)最大。

题解

  对于任意一位(个十百千万),我们可以得出结论:最大的拆分一定是拆出一个9来,也就是求出最大的99...9999。

代码

ll n,a,b,ans;

ll solve(ll x) {
	ll res = 0;
	while(x) {
		res += x%10;
		x /= 10;
	}	
	return res;
}

ll k1,k2;

int main()
{
	cin>>n;
	k1 = n;
	ll k = 9;
	while(k1>k) {
		k2 += k;
		k1 -= k;
		k *= 10;
	}
	ans = solve(k1)+solve(k2);
	cout<<ans;
	return 0;
}

 

C. Maximum Subrectangle

题目

  给定一个长度为n的数列a, 和一个长度为m的数列b, 再让它们形成一个n*m的矩阵c, 其中c(i,j) = a(i)*b(j)。要求一个子矩阵,使其和<x,并且面积尽量大。问最大面积是多少。

题解

  由于c矩阵形成的性质,子矩阵的和就是对应的a和b数组前缀和子序列的乘积。

  因为n和m不大,所以可以枚举1-2000所有长度,穷举出符合条件的面积最大的子矩形。

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <stack>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <cmath>
using namespace std;

#define INIT(x) memset(x,0,sizeof(x))
#define eps 1e-8
#define next next_
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x7fffffff;
const int inf = 0x3f3f3f3f;
const int maxn = 200005;
const int N = 105;

inline void read(ll &x) {
    ll f=1;x=0;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    x*=f;
}

ll n,a[maxn],b[maxn],x,s1[maxn],s2[maxn],m,ans;
vector<ll> e1,e2;

ll check(bool flag,int p,int size) {
	ll res = INF;
	if(flag==0)
		for(int i=p;i<=size;i++) {
			res = min(res,s1[i]-s1[i-p]);
		}
	else
		for(int i=p;i<=size;i++) {
			res = min(res,s2[i]-s2[i-p]);
		}
	return res;
}

int main()
{
	read(n), read(m);
	for(int i=1;i<=n;i++)	read(a[i]),s1[i] = s1[i-1] + a[i];
	for(int i=1;i<=m;i++)	read(b[i]),s2[i] = s2[i-1] + b[i];
	read(x);
	for(int i=1;i<=n;i++) {
		e1.push_back(check(0,i,n));
	}
	for(int i=1;i<=m;i++) {
		e2.push_back(check(1,i,m));
	}
	for(int i=0;i<n;i++) {
		for(int j=0;j<m;j++) {
			if(e1[i]*e2[j]<=x) {
				ans = max(ans,ll(i+1)*(j+1));
			}
		}
	}
	cout<<ans<<endl;
	return 0;
}

D. Social Circles

题目

  有n个人,他们每个人对自己座位左右两边空椅子的数量都有要求。

  第i个人要求自己左边有l[i]个空椅子,右边有r[i]个空椅子。

  他们要求做成若干个环形,当一个人自己形成一个环时,他的左右两边就是同一边。

题解

  首先将L和R数组从大到小排序,对于最大的l和r,我们优先把它们配对。由于允许形成若干个环,也可以自环,所以最优解一定是将最大的l和r配对,次大的l和r配对,依此类推。

  每次配对需要的椅子数量就是max(l,r)+1, +1表示这个人本身坐的椅子。

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <stack>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <cmath>
using namespace std;

#define INIT(x) memset(x,0,sizeof(x))
#define eps 1e-8
#define next next_
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x7fffffff;
const int inf = 0x3f3f3f3f;
const int maxn = 200005;
const int N = 105;

inline void read(ll &x) {
    ll f=1;x=0;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    x*=f;
}

ll n,l,r;
bool vis[maxn];
struct node{
	ll l,r,id;
	bool operator<(const node&b)const{
		return l>b.l;
	}
}a[maxn];

struct node2{
	ll l,r,id;
	bool operator<(const node2&b)const{
		return r>b.r;
	}
}b[maxn];

int main()
{
	read(n);
	for(int i=0;i<n;i++) {
		read(a[i].l),read(a[i].r),a[i].id=i;
		b[i].l = a[i].l, b[i].r = a[i].r,b[i].id=i;
	}
	sort(a,a+n);
	sort(b,b+n);
	ll ans = 0;
	for(int i=0;i<n;i++) {
		ans += max(a[i].l,b[i].r)+1;
	}
	cout<<ans<<endl;
	return 0;
}


E. Sergey and Subway

题目

  给定一棵树,其中有n-1条边,给出所有边的起点和终点。

  现在要加上一些边,假如原来(u,v)相连,(v,w)相连,那么就在(u,w)之间连一条边。

  问加上边后,树上所有点对之间距离的和。

题解

  在加边之前,对于集合A和B,它们用e来相连,那么对于这条边e,经过的次数就是size(a) * size(b)。

                                     

 

  对于一个节点来说,假如以该节点为根的子树大小为x,由于是一棵树,那么它的父亲到它只有一条边,这条边会经过 size[x] * (n-size[x]) 次。

  在加边之后,如果原树两点间距离为奇数,那么至少要经过一条老边(类似1-2-3-4-5这种情况),而由于两两相邻的边会增加一条新边,所以经过的边数为 (原来的+1)/2 ,而偶数边则是直接除以2。

å¨è¿éæå¥å¾çæè¿°

  然后就到了重点发现了:树上距离为奇数的两个点,它们深度的奇偶性必然不同(只能异色)!所以对于上一种原距离为奇数的点,只需加上 黑色点*白色点 的个数。

  最终结果除以2即可。

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <stack>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <cmath>
using namespace std;

#define INIT(x) memset(x,0,sizeof(x))
#define eps 1e-8
#define next next_
#define size size_
typedef long long ll;
typedef unsigned long long ull;
const ll INF = 0x7fffffff;
const ll inf = 0x3f3f3f3f;
const ll maxn = 200005;
const ll N = 105;

inline void read(ll &x) {
    ll f=1;x=0;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    x*=f;
}

vector<ll> e[maxn];
ll n,depth[maxn],size[maxn];

void dfs(ll now,ll fa) {
	for(auto i:e[now]) {
		if(i!=fa) {
			depth[i] = depth[now] + 1;
			dfs(i,now);
			size[now] += size[i];
		}
	}
}

ll calc() {
	ll res = 0,odd = 0;
	for(int i=2;i<=n;i++) {
		res += size[i] * (n-size[i]);
		if(depth[i] & 1)	odd++;
	}
	res += odd * (n-odd);
	return res;
}

int main() {
	read(n);
	for(int i=0;i<n-1;i++) {
		ll x,y;
		read(x), read(y);
		e[x].push_back(y), e[y].push_back(x);
	}	
	for(int i=1;i<=n;i++)	size[i] = 1;
	dfs(1,-1);
	ll ans = calc();
	cout<<ans/2<<endl;
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

总想玩世不恭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值