传送门:http://codeforces.com/contest/1060
目录
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;
}