Codeforces Round #698 (Div. 2) 题解

A

给你一个单调不减的序列,问最多能分割成几个严格单调的子序列。


注意到序列个数与出现次数最多的元素有关,直接统计即可。

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
using namespace std;

const int N=110;

template <class I>
inline void read(I &z)
{
    z=0;
    char c=getchar();int base=1;
    while (!isdigit(c) && c!='-') c=getchar();
    if (c=='-') c=getchar(),base=-1;
    while (isdigit(c)) z=z*10+c-'0',c=getchar();
    z*=base;
}

int n,T,cnt[N],ans,x;

int main(int argc, char const *argv[])
{
    read(T);
    while (T--)
    {
        read(n);
        ans=-1;
        for (int i=1;i<=n;++i) cnt[i]=0;
        for (int i=1;i<=n;++i)
        {
            read(x);
            ++cnt[x];
            ans=max(ans,cnt[x]);
        }
        printf("%d\n",ans);
    }
    return 0;
}

B

给你一个数\(q\),问能否拆分成多个包含数码\(d\)的数的和。


注意到当\(q\)大于\(10*d\)时,可以将\(q\)拆分成一个个位为\(d\)的两位数和一个十位为\(d\)的数(或者\(q\)本身合法)。当\(q\)小于\(10*d\)时,可以被拆分成一堆\(d\)和一个\(10\)的倍数,判断一下即可。

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
using namespace std;


template <class I>
inline void read(I &z)
{
    z=0;
    char c=getchar();int base=1;
    while (!isdigit(c) && c!='-') c=getchar();
    if (c=='-') c=getchar(),base=-1;
    while (isdigit(c)) z=z*10+c-'0',c=getchar();
    z*=base;
}

int T,q,d,x;

int main(int argc, char const *argv[])
{
    read(T);
    while (T--)
    {
        read(q),read(d);
        for (int i=1;i<=q;++i)
        {
            read(x);
            int flag=0;
            for (int j=1;j<=9;++j)
            {
                if (x-j*d<0) break;
                if ((x-j*d)%10==0)
                {
                    flag=1;
                    break;
                }
            }
            if (x>=10*d) flag=1;
            if (flag) printf("YES\n"); else printf("NO\n");
        }

    }
    return 0;
}

C

给出一个数轴上每个点到其他点的距离和,判断是否存在合法的且关于原点对称的长度为\(2*n\)的序列。


排序去重后只要考虑正半轴的部分,距离越小的点离原点越近。做差分之后相邻的两个点之间相差了\(2*i\)\(d_i\)

#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
#include<cmath>
#define LL long long
using namespace std;

template <class I>
inline void read(I &z)
{
    z=0;
    char c=getchar();int base=1;
    while (!isdigit(c) && c!='-') c=getchar();
    if (c=='-') c=getchar(),base=-1;
    while (isdigit(c)) z=z*10+c-'0',c=getchar();
    z*=base;
}

const int N=200010;

LL T,n,len,a[N],b[N],d;

int main(int argc, char const *argv[])
{
    read(T);
    while (T--)
    {
        read(n);
        for (int i=1;i<=(n<<1);++i) read(a[i]);
        sort(a+1,a+n*2+1);
        len=unique(a+1,a+n*2+1)-a-1;
        if (len!=n)
        {
            printf("NO\n");
            continue;
        }

        int flag=0;

        d=0,b[1]=0;
        for (int i=1;i<n;++i)
        {
            if ((a[i+1]-a[i])%(i<<1))
            {
                flag=1;
                break;
            }
            b[i]=(a[i+1]-a[i])/(i<<1);
        }
        if (flag)
        {
            printf("NO\n");
            continue;
        }
        for (int i=2;i<n;++i) d+=(b[i]+=b[i-1]);
        d+=b[1];
        if (a[1]-d*2>0 && (a[1]-d*2)%(n*2)==0) printf("YES\n"); else printf("NO\n");
    }
    return 0;
}

D

在黑板上有\(n\)个各不相同的整数\(a_i\),你可以任取两个数\(x\)\(y\),写上\(2x-y\),且不擦掉\(x\)\(y\),问一系列操作后能否获得给定的数\(k\)


注意到\(2x-y\)可以写成\(2(x-y)+y\),一系列操作后得到的数一定可以写成\(a_t\)加上\(a_i-a_j\)的线性组合,而\(a_i-a_j\)可以用\(a_i-a_{i+1}\)线性表示。枚举\(a_t\)用裴蜀定理判断即可。

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#define LL long long
using namespace std;

const int N=200010;

template <class I>
inline void read(I &z)
{
    z=0;
    char c=getchar();int base=1;
    while (!isdigit(c) && c!='-') c=getchar();
    if (c=='-') c=getchar(),base=-1;
    while (isdigit(c)) z=z*10+c-'0',c=getchar();
    z*=base;
}

LL gcd(LL x,LL y) { return (!y)?x:gcd(y,x%y); }

LL n,k,T,x,y,a[N],b[N],d;

int main(int argc, char const *argv[])
{
    read(T);
    while (T--)
    {
        read(n),read(k);
        for (int i=1;i<=n;++i) read(a[i]);
        for (int i=1;i<n;++i) b[i]=a[i+1]-a[i];
        d=b[1];
        for (int i=2;i<n;++i) d=gcd(d,b[i]);
        int flag=0;
        for (int i=1;i<=n;++i) if ((k-a[i])%d==0) { flag=1; break; }
        printf(flag?"YES\n":"NO\n");
    }
    return 0;
}

E

给你一个长度为\(n\)\(01\)串和\(q\)个询问,每次询问时要保证区间内仅有\(0\)\(1\),询问完后可以改变区间内严格小于\(1/2\)区间长度个数,问能否将给定串变成目标串。


倒着做,线段树维护区间覆盖区间和,贪心地去选\(0\)还是\(1\)。看最后能否将目标串还原成给定串。记得清零。

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define LL long long
#define NO { printf("NO\n"); return; }
using namespace std;

const int N=200010;

template <class I>
inline void read(I &z)
{
    z=0;
    char c=getchar();int base=1;
    while (!isdigit(c) && c!='-') c=getchar();
    if (c=='-') c=getchar(),base=-1;
    while (isdigit(c)) z=z*10+c-'0',c=getchar();
    z*=base;
}

struct Q
{
    int l,r;
}b[N];

int n,q,T;
char s1[N],s2[N];

struct node
{
    int sum;
    int delta;//1 or 2  (&1)
};
node a[N<<2];

inline void pushup(int cur) { a[cur].sum=a[cur<<1].sum+a[cur<<1|1].sum; }

inline void pushdown(int cur,int l,int r)
{
    int mid=l+r>>1;
    a[cur<<1].sum=(mid-l+1)*(a[cur].delta&1),a[cur<<1].delta=a[cur].delta;
    a[cur<<1|1].sum=(r-mid)*(a[cur].delta&1),a[cur<<1|1].delta=a[cur].delta;
    a[cur].delta=0;
}

void build(int cur,int l,int r)
{
    a[cur].sum=a[cur].delta=0;
    if (l<r)
    {
        int mid=l+r>>1;
        build(cur<<1,l,mid),build(cur<<1|1,mid+1,r);
        pushup(cur);
    }
    else a[cur].sum=s2[l]-'0';
}

int inquire(int cur,int l,int r,int L,int R)
{
    if (L<=l && r<=R) return a[cur].sum;
    if (a[cur].delta) pushdown(cur,l,r);
    int ans=0,mid=l+r>>1;
    if (L<=mid) ans+=inquire(cur<<1,l,mid,L,R);
    if (R>mid) ans+=inquire(cur<<1|1,mid+1,r,L,R);
    return ans;
}

void update(int cur,int l,int r,int L,int R,int x)
{
    if (L<=l && r<=R)
    {
        a[cur].sum=(r-l+1)*x;
        a[cur].delta=2-x;
        return;
    }
    if (a[cur].delta) pushdown(cur,l,r);
    int mid=l+r>>1;
    if (L<=mid) update(cur<<1,l,mid,L,R,x);
    if (R>mid) update(cur<<1|1,mid+1,r,L,R,x);
    pushup(cur);
}

void work()
{
    read(n),read(q);
    scanf("%s",s1+1),scanf("%s",s2+1);
    build(1,1,n);
    for (int i=1;i<=q;++i) read(b[i].l),read(b[i].r);
    for (int i=q;i;--i)
    {
        int l=b[i].l,r=b[i].r,t=inquire(1,1,n,l,r);
        if ((t<<1)==r-l+1) NO
        if ((t<<1)<r-l+1) update(1,1,n,l,r,0);
        else update(1,1,n,l,r,1);
    }  
    for (int i=1;i<=n;++i) if (s1[i]-'0'!=inquire(1,1,n,i,i)) NO
    printf("YES\n");
}

int main(int argc, char const *argv[])
{
    read(T);
    while (T--)
        work();
    return 0;
}

F

在一个平面上给你\(n\)个点,问你是否存在一个合法排列,使相邻的两两组成的向量之间的夹角严格大于\(90^{\circ}\)


注意到点\(A_{i},A_{i+1},A_{i+2}\)构成的三角形中只能有一个钝角。故可以通过调整顺序使得其合法。于是可以一个一个将点加入序列,并逐步调整。

#include<cstdio>
#include<algorithm>
#include<cctype>
#define LL long long
using namespace std;

template <class I>
inline void read(I &z)
{
    z=0;
    char c=getchar();int base=1;
    while (!isdigit(c) && c!='-') c=getchar();
    if (c=='-') c=getchar(),base=-1;
    while (isdigit(c)) z=z*10+c-'0',c=getchar();
    z*=base;
}

const int N=5010;

struct PI
{
    LL x,y;
    PI (LL xx=0,LL yy=0):x(xx),y(yy) {}
    LL operator * (PI p) { return x*p.x+y*p.y; }
    PI operator + (PI p) { return PI(x+p.x,y+p.y); }
    PI operator - (PI p) { return PI(x-p.x,y-p.y); }
};

LL c[N],x,y,n;

PI a[N];

int main(int argc, char const *argv[])
{
    read(n);
    for (int i=1;i<=n;++i)
    {
        c[i]=i;
        read(x),read(y);
        a[i]=PI(x,y);
    }
    for (int i=3;i<=n;++i)
        for (int j=i;j>=3;--j)
            if ((a[j]-a[j-1])*(a[j-2]-a[j-1])<=0)
                swap(a[j],a[j-1]),swap(c[j],c[j-1]); else break;
    for (int i=1;i<=n;++i) printf("%lld ",c[i]);
    return 0;
}
posted @ 2021-02-01 00:17  Harexx  阅读(51)  评论(0)    收藏  举报