Codeforces Round #466 (Div. 2)

(题目真是大水,居然没有打,气人)

A. Points on the line

题意:n个点,删除一些点,使得剩下点两两距离不超过d,求删除点的最少个数

题解:暴力即可

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int Max(int a,int b){return a>b?a:b;}
inline int read()
{
    int x=0;char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x;
}
int main()
{
    int n,d,a[105],ans=-1;
    n=read();d=read();
    for(int i=1;i<=n;i++) a[i]=read();
    sort(a+1,a+1+n);
    for(int i=1;i<=n;i++)
    {
        for(int j=n;j>=i;j--)
        {
            if(a[j]-a[i]<=d)
            {
                ans=Max(ans,j-i+1);
                break;
            }
        }
    }
    printf("%d",n-ans);
    return 0;
}
View Code

B. Our Tanya is Crying Out Loud

题意:一个数初始为n,可以将它减1(花费A代价),或除以k(必须整除,花费B代价),求最小代价

题解:最优策略肯定是先减到能除的最大值,然后除,然后继续减,直到除比减花费更大时,剩下全减,最坏复杂度是logn的,k==1时特判

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
inline long long read()
{
    long long x=0;char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x;
}
long long n,k,A,B,ans,now;
int main()
{
    n=read();k=read();A=read();B=read();
    if(k==1)
    {
        printf("%I64d ",(n-1)*A);
        return 0;
    }
    now=n;
    while(now>1)
    {
        ans+=(now%k)*A;now-=now%k;
        if(now==1) break;
        if((now-now/k)*A<B)
        {
            ans+=(now-1)*A;
            break;
        }
        ans+=B;
        now/=k;
    }
    printf("%I64d",ans);
    return 0;
}
View Code

C. Phone Numbers

题意:给你n,k和长度为n的字符串s,求一个由s中字母组成的,长度为k,字典序最小的字符串t,使得t的字典序大于s

题解:把s中所含字母按字典序排个序,然后从后往前枚举t的哪一位大于s

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
inline int read()
{
    int x=0;char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x;
}
int n,k,r[2005],cnt,has[2005];
char s[100005];
bool vis[1000];
int main()
{
    n=read();k=read();
    scanf("%s",s);
    for(int i=0;i<n;i++) if(!vis[(int)(s[i])]) r[++cnt]=(int)(s[i]),vis[(int)(s[i])]=1;
    sort(r+1,r+cnt+1);
    for(int i=1;i<=cnt;i++) has[r[i]]=i;
    if(k>n)
    {
        printf("%s",s);
        for(int i=n;i<k;i++) printf("%c",(char)(r[1]));
        return 0;
    }
    for(int i=k-1;i>=0;i--)
    {
        if(has[(int)(s[i])]!=cnt)
        {
            for(int j=0;j<i;j++) printf("%c",s[j]);
            printf("%c",(char)(r[has[(int)(s[i])]+1]));
            for(int j=i+1;j<k;j++) printf("%c",(char)(r[1]));
            break;
        }
    }
    return 0;
}
View Code

D. Alena And The Heater

题意:给定数组a,b',和一系列与l,r有关的运算规律,求l,r,使得用a造出的数组b等于b',保证有解

题解:b'中每一位都可以转换成和l,r有关的不等式,随便求求就好了

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int Min(int a,int b){return a<b?a:b;}
int Max(int a,int b){return a>b?a:b;}
inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x*f;
}
int n,a[100005],b[100005],ll=-1000000001,lr=1000000000,rl=-1000000000,rr=1000000001,len;
int main()
{
    int ma,mi;
    char B[100005];
    n=read();for(int i=1;i<=n;i++) a[i]=read();
    scanf("%s",B);
    len=strlen(B);
    for(int i=0;i<len;i++) b[i+1]=B[i]-'0';
    for(int i=5,j;i<=n;i++)
    {
        ma=-1000000005;mi=1000000005;
        for(int j=i;j>=i-4;j--) mi=Min(a[j],mi),ma=Max(a[j],ma);
        if(b[i]==b[i-1])
        {
            for(j=i-2;j>=i-4;j--) if(b[j+1]!=b[j]) break;
            if(j<i-4)
            {
                if(b[i]) rl=Max(rr,ma);
                else lr=Min(ll,mi);
            }
        }
        else
        {
            if(b[i]) ll=Max(ll,ma);
            else rr=Min(rr,mi);
        }
    }
    printf("%d %d",ll+1,rr-1);
    return 0;
}
View Code

E. Cashback

题意:给定一段序列,将他们分为诺干段,每一段的价值为这段数字总和减去前(它的长度/c)小的值

题解:DP,dp[i]表示断点为i,一定是分成长度为c比较赚,转移:dp[i]=Min(dp[i-1]+a[i],dp[i-c]+sum[i]-sum[i-c]-(i-c到c的最小值))最小值单调队列(或rmq)维护即可

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
long long Min(long long a,long long b){return a<b?a:b;}
inline long long read()
{
    long long x=0;char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x;
}
long long n,c,a[100005],dp[100005],que[100005],cnt,tail=1,sum[100005];
void xiu(long long x,long long now)
{
    que[++cnt]=x;
    while(cnt>tail&&a[que[cnt]]<=a[que[cnt-1]]) que[--cnt]=que[cnt+1];
    while(now>que[tail]&&tail<=cnt) tail++;
}
int main()
{
    n=read();c=read();
    for(long long i=1;i<=n;i++) a[i]=read(),sum[i]=sum[i-1]+a[i];
    for(long long i=1;i<c&&i<=n;i++) dp[i]=dp[i-1]+a[i],xiu(i,0);
    for(long long i=c;i<=n;i++) xiu(i,i-c+1),dp[i]=Min(dp[i-1]+a[i],dp[i-c]+sum[i]-sum[i-c]-a[que[tail]]);
    printf("%I64d\n",dp[n]);
    return 0;
}
View Code

F. Machine Learning

题意:给你一个数组,和q次操作,单点修改或者查询一段区间的mex值(设区间内i的出现次数为ci,mex值为集合c与正整数集的补集的最小值)

题解:带修莫队+简单暴力,稍微离散一下,因为ci最多有根号n种,复杂度O(n^(5/3)+n根号n)(代码巨丑无比)

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
inline int read()
{
    int x=0;char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x;
}
struct xun{
    int l,r,t,id;
}q[100005];
int n,m,c[100005],be[100005],cnt1,cnt2=1,xiu[3][100005],sum[200005],ans[100005],ansum[100005],nnum[200005],anum[200005],cnu;
bool cmp(xun a,xun b){return be[a.l]==be[b.l]?(be[a.r]==be[b.r]?a.t<b.t:a.r<b.r):a.l<b.l;}
void rev(int x,int add)
{
    ansum[sum[x]]--;
    sum[x]+=add;
    ansum[sum[x]]++;
}
void rev1(int x,int l,int r)
{
    int a=c[xiu[0][x]],b=xiu[1][x];xiu[2][x]=a;
    c[xiu[0][x]]=b;
    if(xiu[0][x]>=l&&xiu[0][x]<=r)
    {
        ansum[sum[a]]--;ansum[--sum[a]]++;
        ansum[sum[b]]--;ansum[++sum[b]]++;
    }
}
void rev2(int x,int l,int r)
{
    int a=c[xiu[0][x]],b=xiu[2][x];
    c[xiu[0][x]]=b;
    if(xiu[0][x]>=l&&xiu[0][x]<=r)
    {
        ansum[sum[a]]--;ansum[--sum[a]]++;
        ansum[sum[b]]--;ansum[++sum[b]]++;
    }
}
bool check(int x,int s)
{
    if(nnum[x]<c[s]) return 1;
    else return 0;
}
bool check2(int x,int s)
{
    if(nnum[x]<xiu[1][s]) return 1;
    else return 0;
}
int main()
{
    int l,r,now=0,mid;
    n=read();m=read();
    int ttt=pow(n,2.0/3.0);
    for(int i=1;i<=n;i++) c[i]=read(),be[i]=i/ttt,nnum[++cnu]=c[i];
    for(int i=1,s;i<=m;i++)
    {
        s=read();
        if(s==1) q[++cnt1].l=read(),q[cnt1].r=read(),q[cnt1].t=cnt2,q[cnt1].id=cnt1;
        else xiu[0][++cnt2]=read(),xiu[1][cnt2]=read(),nnum[++cnu]=xiu[1][cnt2];
    }
    sort(nnum+1,nnum+cnu+1);
    for(int i=1,mmax=-1;i<=cnu;i++)
    {
        if(nnum[i]>mmax) mmax=nnum[i],now++;
        anum[i]=now;
    }
    for(int i=1,mid;i<=cnu;i++)
    {
        l=1,r=cnu;
        if(i<=n)
        {
        while(l<r)
        {
            mid=l+r>>1;
            if(check(mid,i)) l=mid+1;
            else r=mid;
        }
        c[i]=anum[l];
        }
        else
        {
        while(l<r)
        {
            mid=l+r>>1;
            if(check2(mid,i-n+1)) l=mid+1;
            else r=mid;
        }
        xiu[1][i-n+1]=anum[l];
        }
    }
    sort(q+1,q+1+cnt1,cmp);
    l=1;r=0;now=1;
    for(int i=1;i<=cnt1;i++)
    {
        while(r<q[i].r) rev(c[++r],1);
        while(l>q[i].l) rev(c[--l],1);
        while(l<q[i].l) rev(c[l++],-1);
        while(r>q[i].r) rev(c[r--],-1);
        while(now<q[i].t) rev1(++now,l,r);while(now>q[i].t) rev2(now--,l,r);
        for(int j=1;j<=200000;j++){if(!ansum[j]){ans[q[i].id]=j;break;}}
    }
    for(int i=1;i<=cnt1;i++) printf("%d\n",ans[i]);
    return 0;
}
View Code

 

posted @ 2018-02-27 11:39  zzpcd  阅读(113)  评论(0编辑  收藏  举报