Codeforces Round #513 游记

Codeforces Round #513 游记

A - Phone Numbers

题目大意:

电话号码是8开头的\(1\)位数字。告诉你\(n(n\le100)\)个数字,每个数字至多使用一次。问最多能凑出多少个电话号码。

思路:

统计8出现的次数,如果有多余的8不能作为开头,那么就将其放到后面去

源代码:

#include<cstdio>
#include<cctype>
#include<algorithm>
inline int getint() {
    register char ch;
    while(!isdigit(ch=getchar()));
    register int x=ch^'0';
    while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    return x;
}
inline int getdigit() {
    register char ch;
    while(!isdigit(ch=getchar()));
    return ch^'0';
}
int cnt[2];
int main() {
    const int n=getint();
    for(register int i=0;i<n;i++) cnt[getdigit()==8]++;
    while(cnt[0]<cnt[1]*10) {
        cnt[1]--;
        cnt[0]++;
    }
    printf("%d\n",std::min(cnt[1],cnt[0]/10));
    return 0;
}

B - Maximum Sum of Digits

题目大意:

定义\(S(x)\)为\(x\)各数位之和。给定\(n(n\le10^{12})\),\(a+b=n\),求\(S(a)+S(b)\)的最大值。

思路:

如果这一位\(x\)不是第一位,且这一位不是\(9\),就把这一位当做\(10+x\),并把上一位\(-1\)。

源代码:


 #include<cstdio>
#include<cctype>
typedef long long int64;
inline int64 getint() {
    register char ch;
    while(!isdigit(ch=getchar()));
    register int64 x=ch^'0';
    while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    return x;
}
int main() {
    int64 n=getint();
    int ans=0;
    for(;n;n/=10) {
        ans+=n%10;
        if(n%10!=9&&n/10!=0) {
            ans+=10;
            n-=10;
        }
    }
    printf("%d\n",ans);
    return 0;
}

C - Maximum Subrectangle

题目大意:

给定\(a_{1\sim n},b_{1\sim m}(n,m\le2000)\)和\(x\),\(c_{i,j}=a_ib_j\)。求\(c\)的一个最大子矩阵,使得矩阵内数字和\(\le x\)。输出面积的最大值。

思路:

预处理\(a/b\)连续\(i\)个数之和的最小值。然后枚举矩形长宽即可。

源代码:

#include<cstdio>
#include<cctype>
#include<climits>
#include<algorithm>
inline int getint() {
    register char ch;
    while(!isdigit(ch=getchar()));
    register int x=ch^'0';
    while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    return x;
}
typedef long long int64;
const int N=2001;
int a[N],b[N],min1[N],min2[N];
int main() {
    const int n=getint(),m=getint();
    for(register int i=1;i<=n;i++) a[i]=getint();
    for(register int i=1;i<=m;i++) b[i]=getint();
    const int x=getint();
    for(register int i=1;i<=n;i++) {
        min1[i]=INT_MAX;
        int sum=0;
        for(register int j=1;j<i;j++) sum+=a[j];
        for(register int j=i;j<=n;j++) {
            sum-=a[j-i];
            sum+=a[j];
            min1[i]=std::min(min1[i],sum);
        }
    }
    for(register int i=1;i<=m;i++) {
        min2[i]=INT_MAX;
        int sum=0;
        for(register int j=1;j<i;j++) sum+=b[j];
        for(register int j=i;j<=m;j++) {
            sum-=b[j-i];
            sum+=b[j];
            min2[i]=std::min(min2[i],sum);
        }
    }
    int ans=0;
    for(register int i=1;i<=n;i++) {
        for(register int j=1;j<=m;j++) {
            if((int64)min1[i]*min2[j]<=x) {
                ans=std::max(ans,i*j);
            }
        }
    }
    printf("%d\n",ans);
    return 0;
}

D - Social Circles

题目大意:

有\(n(n\le10^5)\)个人排成一圈,第\(i\)个人要求自己左边空出\(l_i\)个座位,右边空出\(r_i(l_i,r_i\le10^9)\)个座位。问最少需要安排多少个座位。

思路:

一开始先假设每个人都占了\(l_i+r_i+1\)个位置。考虑怎样安排相邻人的顺序,并合并相邻人的\(l_i,r_i\)使得答案最优。

将所有\(l_i,r_i\)分别排序,将对应的\(l_i,r_i\)合并一定是最优的(想一想这是为什么)。

源代码:

#include<cstdio>
#include<cctype>
#include<algorithm>
inline int getint() {
    register char ch;
    while(!isdigit(ch=getchar()));
    register int x=ch^'0';
    while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    return x;
}
typedef long long int64;
const int N=1e5+1;
int l[N],r[N];
int main() {
    const int n=getint();
    int64 ans=0;
    for(register int i=1;i<=n;i++) {
        l[i]=getint();
        r[i]=getint();
        ans+=l[i]+r[i]+1;
    }
    std::sort(&l[1],&l[n]+1);
    std::sort(&r[1],&r[n]+1);
    for(register int i=1;i<=n;i++) {
        ans-=std::min(l[i],r[i]);
    }
    printf("%lld\n",ans);
    return 0;
}

E - Sergey and Subway

题目大意:

给定一棵\(n(n\le2\times10^5)\)个点的树,每条边权都是\(1\)。原树上的边称作老边,两个点之间可以连一条新边当且仅当原来两个点之间距离为\(2\)。问最后所有点对之间最短路之和是多少?

思路:

首先不考虑新边,我们可以考虑每条边的贡献计算出所有点对距离值和\(sum\)。

而经过加新边的操作后,原来距离为偶数的点对距离\(/2\),奇数点对距离\(/2+1\)。而我们可以通过黑白染色后黑/白点的数目统计出奇数距离的点对数目。

源代码:

#include<cstdio>
#include<cctype>
#include<vector>
inline int getint() {
    register char ch;
    while(!isdigit(ch=getchar()));
    register int x=ch^'0';
    while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    return x;
}
using int64=long long;
const int N=2e5+1;
std::vector<int> e[N];
inline void add_edge(const int &u,const int &v) {
    e[u].push_back(v);
    e[v].push_back(u);
}
int64 ans;
bool col[N];
int n,size[N],cnt[2],par[N];
void dfs(const int &x,const int &par) {
    size[x]=1;
    ::par[x]=par;
    cnt[col[x]=!col[par]]++;
    for(auto &y:e[x]) {
        if(y==par) continue;
        dfs(y,x);
        size[x]+=size[y];
        ans+=(int64)size[y]*(n-size[y]);
    }
}
int main() {
    n=getint();
    for(register int i=1;i<n;i++) {
        add_edge(getint(),getint());
    }
    dfs(1,0);
    ans=(ans+(int64)cnt[0]*cnt[1])/2;
    printf("%lld\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/skylee03/p/9742941.html

时间: 2024-08-01 08:52:08

Codeforces Round #513 游记的相关文章

Codeforces Round #513解题报告(A~E)By cellur925

我是比赛地址 A:Phone Numbers $Description$:给你一串数字,问你能组成多少开头为8的11位电话号码. $Sol$:统计8的数量,与$n$%11作比较. 1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 5 using namespace std; 6 7 int n,len,cnt,ans; 8 char ch[1000]; 9 10 int main() 11 {

Codeforces Round #513 D - Social Circles(贪心)

题目大意: 有n(n≤105)个人排成一圈,第i个人要求自己左边空出li个座位,右边空出ri(li,ri≤109)个座位.问最少需要安排多少个座位.思路: 一开始先假设每个人都占了li+ri+1个位置.考虑怎样安排相邻人的顺序,并合并相邻人的li,ri使得答案最优.将所有li,ri分别排序,将对应的li,ri合并一定是最优的(想一想这是为什么). #include <iostream> #include <iomanip> #include <algorithm> #i

Codeforces Round #513(Div.1+Div.2)

闲谈: 重新写博客的第一场比赛,感觉炸裂,成功被Rose和xgcD飞 A 题目: 给出一段长为n个数字字符串,求出能用里面的字符来构成多少个长度为11且开头字符为8的字符串 题解: 直接在n/11和8出现的数量中取min就可以了 参考代码: #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace

[Codeforces Round #513 by Barcelona Bootcamp (rated, Div. 1 + Div. 2) ](A~E)

A: 题目大意:给你一个数字串,每个数字只可以用一次,求最多可以组成多少个电话号码(可以相同),电话号码第一个数字为$8$,且长度为$11$ 题解:限制为$8$的个数和总长度,直接求 卡点:无 C++ Code: #include <cstdio> #include <algorithm> #define maxn 1000 inline int min(int a, int b) {return a < b ? a : b;} inline int max(int a, i

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

A.Phone Numbers 题意:给你n个数字,每个数字最多只能用一次,问你最多能组成以8开头的11位电话号码有多少个 思路:模拟即可,注意char数组读入是从0下标开始的(在这里被hack了...) 1 #include<bits/stdc++.h> 2 int main() 3 { 4 int n,num=0,ans=0; 5 char c[105]; 6 scanf("%d%s",&n,c); 7 for(int i=0;i<n;i++)if(c[i

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

昨天做的,今天才想起来,要写个博客,记一下这种矩阵题怎么做. 首先我没有意识到,每个方向上累和,得到两个累和数组,它们的子序列之积,就是子序列对应的矩形区域范围内所有数字之和,说起来有点抽象,但是举个栗子吧, 就像用例里面的这张提示图,横坐标我选子列2,3,则和为5,纵坐标我选子列1,2,则和为3.那么3和5,乘积为15,而把矩阵中对应区域的和相加,也是15,.则这个问题就容易了:只需要枚举一维数组就可以了.但是,如果枚举一维数组,那岂不是要做一个四重循环?其实不然. 题目要我们获得一个不大于限

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

C - Maximum Subrectangle 因为是两个数组相乘的到的 矩阵所以  a(i ->j)*b(x->y) 的面积 就是   a(i ->j) 的和乘与b(x->y)的和 所以我们枚举 a 序列 从1-n的长度和  B序列同理 然后 枚举两个序列和相乘 找一个最大即可 #include<bits/stdc++.h> using namespace std; #define inf 0x3f3f3f3f #define LL long long #defin

Educational Codeforces Round 21 G. Anthem of Berland(dp+kmp)

题目链接:Educational Codeforces Round 21 G. Anthem of Berland 题意: 给你两个字符串,第一个字符串包含问号,问号可以变成任意字符串. 问你第一个字符串最多包含多少个第二个字符串. 题解: 考虑dp[i][j],表示当前考虑到第一个串的第i位,已经匹配到第二个字符串的第j位. 这样的话复杂度为26*n*m*O(fail). fail可以用kmp进行预处理,将26个字母全部处理出来,这样复杂度就变成了26*n*m. 状态转移看代码(就是一个kmp

Codeforces Round #428 (Div. 2)

Codeforces Round #428 (Div. 2) A    看懂题目意思就知道做了 #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a; i<=b; ++i) #define per(i,b,a) for (int i=b; i>=a; --i