记人生第一次CF体验

新人之前有做过CF题,但由于种种原因,并没有打过。。然后今天正好有一场不肝的div1+div2,说打咱就打。


首先由于题意杀被A坑了好久。。。英语不行啊。。。

题意大概就是给你n个数字,让你求同时最多能构成多少电话号码。电话号码的定义是以8开头,长度为11的一个数列。所以最后就是一个非常显然的结论:\(ans=min(n/11,tim_8)\)...难受啊马飞。。

#include<bits/stdc++.h>
#define ll long long
#define sqr(x) ((x)*(x))
#define lowbit(x) (x&(-x))
#define mid ((l+r)>>1)
#define ls now<<1,l,mid
#define rs now<<1|1,mid+1,r
using namespace std;
const int N=1e6+10,inf=1e9;
inline int read(){
    int x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c<='9'&&c>='0')x=x*10+c-'0',c=getchar();
    return x*f;
}
char s[110];
int n,ss,ans;
int main(){
    n=read();
    scanf("%s",s+1);
    for(int i=1;i<=n;i++)if(s[i]=='8')ss++;
    printf("%d",min(ss,n/11));
}

B题题意大概就是给你一个n,让你找到a,b,a+b=n且a的各位之和与b的各位之和最大。

首先我们有一个非常明显的贪心策略:可以尽可能地选各个数位都为9的数。所以我们可以求出小于等于n的最大的形如999...999的数a,统计答案后再加上n-a的贡献即可。

#include<cstdio>
#include<iostream>
using namespace std;
int main(){
    long long n;
    cin>>n;
    long long a=0,ans=0;
    while(a<=n)a=a*10+9,ans+=9;a/=10;ans-=9;
    long long b=n-a;
    while(b)ans+=(b%10),b/=10;
    cout<<ans;
}

C题就是给定两个数组a,b,长度分别为n,m,同时给一个数x求:

\[max\{(x2-x1+1)*(y2-y1+1)|\sum_{i=x1}^{x2}a[i]*\sum_{j=y1}^{y2}b[j]<=x\} \]

我们可以对于a数组构造一个\(n^2\)的表,存储a每个区间的sum,按sum排序后,求出len的前缀max,然后\(m^2\)枚举b的每个区间,然后找出表中权值小于等于x/sum的max_len,统计答案即可。

#include<bits/stdc++.h>
#define ll long long
#define sqr(x) ((x)*(x))
#define lowbit(x) (x&(-x))
#define mid ((l+r)>>1)
#define ls now<<1,l,mid
#define rs now<<1|1,mid+1,r
using namespace std;
const int N=2010,inf=1e9;
inline int read(){
    int x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c<='9'&&c>='0')x=x*10+c-'0',c=getchar();
    return x*f;
}
int n,m,x,a[N],b[N],suma[N],sumb[N],mx[N*N],tot,ans;
struct fk{
    int len,val;
    friend bool operator<(fk a,fk b){return a.val<b.val;}
}mp[N*N];
int main(){
    n=read();m=read();
    for(int i=1;i<=n;i++)a[i]=read(),suma[i]=suma[i-1]+a[i];
    for(int i=1;i<=m;i++)b[i]=read(),sumb[i]=sumb[i-1]+b[i];
    x=read();
    for(int i=1;i<=n;i++)
        for(int j=i;j<=n;j++)
            mp[++tot]=(fk){j-i+1,suma[j]-suma[i-1]};
    sort(mp+1,mp+tot+1);
    for(int i=1;i<=tot;i++)mx[i]=max(mx[i-1],mp[i].len);
    for(int i=1;i<=m;i++)
        for(int j=i;j<=m;j++){
            int now=sumb[j]-sumb[i-1];
            int id=upper_bound(mp+1,mp+tot+1,(fk){0,x/now})-mp;
            ans=max(ans,mx[id-1]*(j-i+1));
        }
    printf("%d",ans);
}

D题题意大概是说有n个人,每个人有一个Li,Ri,分别表示其左边,右边至少要有多少个空椅子,而且自己要占一个座位。对于此题,考虑贪心。我们可以将L,R两数组排序,然后将L,R值相对位置相同的合并。由于L只能与R合并,所以代价为\(max(L_i,R_i)\),累加后再加上每个人所需的一个座位共n个座位即可。

#include<bits/stdc++.h>
#define ll long long
#define sqr(x) ((x)*(x))
#define lowbit(x) (x&(-x))
#define mid ((l+r)>>1)
#define ls now<<1,l,mid
#define rs now<<1|1,mid+1,r
using namespace std;
const int N=1e5+10,inf=1e9;
inline int read(){
    int x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c<='9'&&c>='0')x=x*10+c-'0',c=getchar();
    return x*f;
}
long long n,l[N],r[N],ans;
int main(){
    n=read();
    for(int i=1;i<=n;i++)l[i]=read(),r[i]=read();
    sort(l+1,l+n+1);sort(r+1,r+n+1);
    for(int i=1;i<=n;i++)ans+=max(l[i],r[i]);
    printf("%I64d",ans+n);
}

然后我A掉这题后,发现分还没C高。。。日。。。

然后时间就不够了。。。以后还是要先看完所有的题后再做啊。。。要善于发现顺序靠后的水题才是王道啊!

posted @ 2018-10-04 21:54  努力进步的肥宅yxc  阅读(115)  评论(0编辑  收藏  举报