码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2018-10-05 12:29:13      阅读:205      评论:0      收藏:0      [点我收藏+]

标签:sort   mem   opened   排序   技术   can   数字   矩阵   bae   

闲谈:

  重新写博客的第一场比赛,感觉炸裂,成功被Rose和xgcD飞


A

题目:

  给出一段长为n个数字字符串,求出能用里面的字符来构成多少个长度为11且开头字符为8的字符串

题解:

  直接在n/11和8出现的数量中取min就可以了

参考代码:

技术分享图片
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
char st[110];
int sum[11];
int main()
{
    int n;
    scanf("%d",&n);
    scanf("%s",st+1);
    memset(sum,0,sizeof(sum));
    for(int i=1;i<=n;i++) sum[st[i]-0]++;
    if(sum[8]==0){printf("0\n");return 0;}
    printf("%d\n",min(sum[8],n/11));
    return 0;
}
A

B

题目:

  给出一个数n,要求求出a,b,满足n=a+b,且a的数字和与b的数字和的和最大,求出最大和

题解:

  直接贪心,让最接近n的...999这样的数作为a,如:n=345,则a就为299,然后将n减去a,得到b,然后再计算数字和,这个数字和一定最大,自行yy

参考代码:

技术分享图片
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
int cnt[21];
LL bin[21];
int main()
{
    LL n;
    scanf("%lld",&n);
    bin[0]=1;
    for(int i=1;i<=13;i++) bin[i]=bin[i-1]*10LL;
    LL x=n;int tot=0;
    while(x!=0){cnt[++tot]=x%10;x/=10;}
    LL ans=0;ans+=cnt[tot]-1+(tot-1)*9;
    n-=bin[tot-1]*LL(cnt[tot])-1;
    tot=0;
    while(n!=0){ans+=n%10;n/=10;}
    printf("%lld\n",ans);
    return 0;
}
B

C

题目:

  给出一个长度为n的数组a,和一个长度为m的数组b,和一个变量x

  已知c[i][j]=a[i]*b[j],求出x1,x2,y1,y2满足$\sum_{i=x1}^{x2}\sum_{j=y1}^{y2}c[i][j]<=x$

  求出最大的(x2-x1+1)*(y2-y1+1)

题解:

  一开始转换成矩阵还更不会做了,我们会发现得到的满足条件的矩阵实际上是$\sum_{i=x1}^{x2}a[i]*\sum_{i=y1}^{y2}b[i]$

  然后我们预处理出b数组所有的子段信息,包括子段长度和子段和,存入一个结构体

  按照和从小到大排序,然后用一个数组len保存前i个子段的最大长度

  我们枚举x1,x2,得到$d=\sum_{i=x1}^{x2}a[i]$,然后用x/d,二分找最接近x/d而且小于等于x/d的子段和,保存位置,因为我们能满足当前位置的子段,说明也能满足前面位置的子段(因为已经按照和从小到大排序了),那么就直接找到这个位置的len,用(x2-x1+1)*len[二分得到的位置]来更新答案即可

参考代码:

技术分享图片
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
LL a[2100],b[2100],s[2100],sb[2100];
struct node
{
    LL d,len;
}B[4100000];
bool cmp(node n1,node n2){return n1.d<n2.d;}
LL Max[4100000];
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]),s[i]=a[i]+s[i-1];
    for(int i=1;i<=m;i++) scanf("%lld",&b[i]),sb[i]=sb[i-1]+b[i];
    int tot=0;
    for(int i=1;i<=m;i++)
    {
        for(int j=i;j<=m;j++) B[++tot]=(node){sb[j]-sb[i-1],j-i+1};
    }
    sort(B+1,B+tot+1,cmp);
    for(int i=1;i<=tot;i++) Max[i]=max(Max[i-1],B[i].len);
    LL x;scanf("%lld",&x);
    LL mmax=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=i;j<=n;j++)
        {
            LL d=x/(s[j]-s[i-1]);
            int l=1,r=tot,ans=0;
            while(l<=r)
            {
                int mid=(l+r)/2;
                if(B[mid].d<=d) l=mid+1,ans=mid;
                else r=mid-1;
            }
            mmax=max(mmax,(j-i+1)*Max[ans]);
        }
    }
    printf("%lld\n",mmax);
    return 0;
}
C

D(*)

题目:

  有很多张椅子,若干个椅子排成一圈,可以排成多个圈

  有n个人,每个人都要坐一个椅子,而且每个人给出l[i],r[i],表示他坐的位置左边要至少有l[i]个空椅子,右边要至少有r[i]个空椅子

  求出至少要用多少个椅子才能满足这n个人的要求

题解:

  贪心,将l和r分别从小到大排序,ans+=max(l[i],r[i]),最后加上n就行了

参考代码:

技术分享图片
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long LL;
int l[110000],r[110000];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d%d",&l[i],&r[i]);
    sort(l+1,l+n+1);sort(r+1,r+n+1);
    LL ans=0;
    for(int i=1;i<=n;i++) ans+=max(l[i],r[i]);
    ans+=n;
    printf("%lld\n",ans);
    return 0;
}
D

E(*)

题目:

  给出一棵n个点的树,两个点之间的距离为(两个点之间的边数+1)/2(向下取整)

  求出所有点对的距离和

题解:

  树形DP

  s[i][k]表示第i棵子树内(不包括i点),(到i点的边数+1)%2=k的点数

  d[i][k]表示第i棵子树内(不包括i点),(到i点的边数+1)%2=k的点到i点的距离和

  然后分情况转移就行了

参考代码:

技术分享图片
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
struct node
{
    int x,y,next;
}a[410000];int len,last[210000];
void ins(int x,int y)
{
    len++;
    a[len].x=x;a[len].y=y;
    a[len].next=last[x];last[x]=len;
}
LL s[210000][2],d[210000][2],ans[210000];
//s[i][k]表示第i棵子树内(不包括i点),(到i点的边数+1)%2=k的点数
//d[i][k]表示第i棵子树内(不包括i点),(到i点的边数+1)%2=k的点到i点的距离和 
void dfs(int x,int fa)
{
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(y==fa) continue;
        dfs(y,x);
        ans[x]+=ans[y];
        ans[x]+=d[x][0]*s[y][1]+d[y][1]*s[x][0];
        ans[x]+=d[x][1]*s[y][0]+d[y][0]*s[x][1];
        ans[x]+=d[x][0]*s[y][0]+d[y][0]*s[x][0];
        ans[x]+=(d[x][1]+s[x][1])*s[y][1]+d[y][1]*s[x][1];
        ans[x]+=d[x][0]+d[x][1]+s[x][1];
        s[x][0]+=s[y][1]+1;
        d[x][0]+=d[y][1]+s[y][1]+1;
        s[x][1]+=s[y][0];
        d[x][1]+=d[y][0];
    }
    ans[x]+=d[x][0]+d[x][1];
}
int main()
{
    int n;
    scanf("%d",&n);
    len=0;memset(last,0,sizeof(last));
    for(int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        ins(x,y);ins(y,x);
    }
    dfs(1,0);
    printf("%lld\n",ans[1]);
    return 0;
}
E

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

标签:sort   mem   opened   排序   技术   can   数字   矩阵   bae   

原文地址:https://www.cnblogs.com/Never-mind/p/9744217.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!