Educational Codeforces Round 81 (Rated for Div. 2)

A. Display The Number (CF 1295 A)

题目大意

\(n\)个火柴棒,问摆出的最大数字是多少?摆出每个数字所需要的火柴棒参照红绿灯。
红绿灯

解题思路

贪心即可。不断放\(1\),最后如果剩下一个火柴棒则最高位变成\(7\)

神奇的代码
#include <bits/stdc++.h>
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<PII> VPII;
typedef vector<LL> VL;
typedef pair<LL,LL> PLL;
typedef vector<PLL> VPLL;

template <typename T>
void read(T &x) {
    int s = 0, c = getchar();
    x = 0;
    while (isspace(c)) c = getchar();
    if (c == 45) s = 1, c = getchar();
    while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    if (s) x = -x;
}

template <typename T>
void write(T x, char c = ' ') {
    int b[40], l = 0;
    if (x < 0) putchar(45), x = -x;
    while (x > 0) b[l++] = x % 10, x /= 10;
    if (!l) putchar(48);
    while (l) putchar(b[--l] | 48);
    putchar(c);
}

int main(void) {
    int kase; read(kase);
    for (int i = 1; i <= kase; i++) {
        int n;
        read(n);
        int a[100500]={0};
        int cnt=-1;
        while(n>=2){
            a[++cnt]=1;
            n-=2;
        }
        if (n==1) a[cnt]=7;
        for(int i=cnt;i>=0;--i) putchar(a[i]+'0');
        puts("");
    }
    return 0;
}


B. Infinite Prefixes (CF 1295 B)

题目大意

给定一个\(01\)\(s\),串\(t\)由串\(s\)不断重复得到,是无限长的。定义函数\(f(x)=cnt_0(x)-cnt_1(x)\),其中\(cnt_0(x)\)表示串\(t\)第一位到第\(x\)\(0\)的个数,\(cnt_1\)同理。给定一个数\(x\),问有多少个\(i\)使得\(f(i)=x\),无限则输出\(-1\)

解题思路

由于\(s\)串是\(t\)串不断重复得到,\(x=f(j)=k*f(n)+f(i)\),其中\(k=\lfloor \frac{j}{n} \rfloor ,i=j\%n\),%是求余,且\(f(0)=0\),所以\(k=\dfrac{x-f(i)}{f(n)}\),对于每一个\(i \in [1,n]\),我们只要判断是否\((x-f(i))*f(n)>0\)\((x-f(i))\%f(n)==0\)即可。当\(f(n)\)\(0\)\(f(1)\)\(f(n)\)中存在等于\(x\)的则答案无限。注意如果\(x=0\)的话还要加上一开始的空串。

神奇的代码
#include <bits/stdc++.h>
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<PII> VPII;
typedef vector<LL> VL;
typedef pair<LL,LL> PLL;
typedef vector<PLL> VPLL;

template <typename T>
void read(T &x) {
    int s = 0, c = getchar();
    x = 0;
    while (isspace(c)) c = getchar();
    if (c == 45) s = 1, c = getchar();
    while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    if (s) x = -x;
}

template <typename T>
void write(T x, char c = ' ') {
    int b[40], l = 0;
    if (x < 0) putchar(45), x = -x;
    while (x > 0) b[l++] = x % 10, x /= 10;
    if (!l) putchar(48);
    while (l) putchar(b[--l] | 48);
    putchar(c);
}

int main(void) {
    int kase; read(kase);
    for (int i = 1; i <= kase; i++) {
        int n;
        LL x;
        read(n);
        read(x);
        char s[n]={0};
        LL sum[n]={0};
        scanf("%s",s);
        sum[0]=(s[0]=='0')?1:-1;
        bool qwq=sum[0]==x?true:false;
        for(int i=1;i<n;++i) {
            sum[i]=sum[i-1]+((s[i]=='0')?1:-1);
            if (sum[i]==x) qwq=true;
        }
        if (sum[n-1]==0&&qwq) {puts("-1"); continue;}
        else if (sum[n-1]==0&&!qwq) {puts("0"); continue;}
        if (x*sum[n-1]<0&&!qwq) {puts("0"); continue;}
        LL ans=0;
        for(int i=0;i<n;++i){
            if ((x-sum[i])*sum[n-1]<0) continue;
            if ((x-sum[i])%sum[n-1]==0) ans++;
        }
        if (x==0) ++ans;
        write(ans,'\n');
    }
    return 0;
}


C. Obtain The String (CF 1295 C)

题目大意

给定两个串\(s,t\),构造一个串\(z\)等于\(t\),每次取\(s\)的子串加到\(z\)串的最后,问最少取多少次\(s\)的子串。子串是指去掉\(s\)串任意个字母,在不改变剩下字母的相对位置得到的串。无法构造输出\(-1\)

解题思路

\(set\)储存\(s\)串中每个字母的位置,记录当前处理的串\(s\)的位置,模拟就好了。当\(t\)串有\(s\)串中不存在的字母则不可构造。

神奇的代码
#include <bits/stdc++.h>
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<PII> VPII;
typedef vector<LL> VL;
typedef pair<LL,LL> PLL;
typedef vector<PLL> VPLL;

template <typename T>
void read(T &x) {
    int s = 0, c = getchar();
    x = 0;
    while (isspace(c)) c = getchar();
    if (c == 45) s = 1, c = getchar();
    while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    if (s) x = -x;
}

template <typename T>
void write(T x, char c = ' ') {
    int b[40], l = 0;
    if (x < 0) putchar(45), x = -x;
    while (x > 0) b[l++] = x % 10, x /= 10;
    if (!l) putchar(48);
    while (l) putchar(b[--l] | 48);
    putchar(c);
}

const int N=1e5+8;

char s[N],t[N];

int main(void) {
    int kase; read(kase);
    for (int i = 1; i <= kase; i++) {
        set<int> pos[26];
        scanf("%s%s",s,t);
        int ls=strlen(s);
        bool sign[27]={0};
        for(int i=0;i<ls;++i) pos[s[i]-'a'].insert(i),sign[s[i]-'a']=1;
        int ans=1,cur=-1;
        int lt=strlen(t);
        bool qwq=true;
        for(int i=0;i<lt;++i){
            int x=t[i]-'a';
            if (sign[x]==false) {qwq=false; break;}
            auto a=pos[x].upper_bound(cur);
            if (a==pos[x].end()){
                ans++;
                cur=(*pos[x].begin());
            }else cur=*a;
        }
        if (qwq) write(ans,'\n');
        else puts("-1");
    }
    return 0;
}


D. Same GCDs (CF 1295 D)

题目大意

给定\(a,m\),求\(\sum\limits_{x=0}^{m-1}[gcd(a,m)=gcd(a+x,m)]\)

解题思路

\(gcd(a,m)=n\),则\(a=k_1\times n,m=k_2\times n\),若\(gcd(a,m)=gcd(a+x,m)\),则\(a+x=k_1\times n+x=k_3\times n\),且\(gcd(k_3,k_2)=1\),即\(k_3\)\(k_2\)互质,其中\(k_1 \leq k_3 \leq \lfloor \dfrac{a+m-1}{x} \rfloor\)。那问题就转化成给定一个数\(m\),求区间\([a,b]\)有多少个数与\(m\)互质,容斥即可。
当然\(\sum\limits_{i=1}^{a}[gcd(i,m)=1]=\sum\limits_{d|m}\mu(d)\times \frac{a}{d}\)莫比乌斯或许也可以

神奇的代码
#include <bits/stdc++.h>
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<PII> VPII;
typedef vector<LL> VL;
typedef pair<LL,LL> PLL;
typedef vector<PLL> VPLL;

template <typename T>
void read(T &x) {
    int s = 0, c = getchar();
    x = 0;
    while (isspace(c)) c = getchar();
    if (c == 45) s = 1, c = getchar();
    while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    if (s) x = -x;
}

template <typename T>
void write(T x, char c = ' ') {
    int b[40], l = 0;
    if (x < 0) putchar(45), x = -x;
    while (x > 0) b[l++] = x % 10, x /= 10;
    if (!l) putchar(48);
    while (l) putchar(b[--l] | 48);
    putchar(c);
}

vector<LL> prim;

LL a,m;

void divide(LL x){
    prim.clear();
    int qwq=sqrt(x);
    for(int i=2;i<=qwq;++i)
        if (x%i==0){
            prim.push_back(i);
            while(x%i==0) x/=i;
        }
    if (x>1) prim.push_back(x);
}

LL solve(LL x){
    vector<LL> que;
    que.push_back(-1);
    for(size_t i=0;i<prim.size();++i){
        int k=que.size();
        for(int j=0;j<k;++j)
            que.push_back(prim[i]*que[j]*(-1));   
    }
    LL ans=0;
    for(size_t i=1;i<que.size();++i)
        ans+=x/que[i];
    return x-ans;
}

int main(void) {
    int kase; read(kase);
    for (int i = 1; i <= kase; i++) {
        read(a);
        read(m);
        LL x=__gcd(a,m);
        LL u=(a+m-1)/x;
        a/=x;
        m/=x;
        divide(m);
        LL ans=solve(u)-solve(a-1);
        write(ans,'\n');
    }
    return 0;
}

~~讲个笑话我内存0 B~~

E. Permutation Separation (CF 1295 E)

题目大意

给定一个排列\(p\),和一个数组\(a\)表示这个排列的每个位置的能量值,要求从中间某个位置把排列分成左右两段,然后把左边的一些数移动到右边,右边的一些数移动到左边,使得左边的所有值小于右边的所有值。某个值移动的代价为该位置的能量值。求满足条件所需要的最小能量值。注意,如果有一边没有数,我们也认为这满足了上述的条件(前提假则整个命题为真嘛)。

解题思路

我们首先发现,如果左边一段的数的个数是确定的,假设是\(k\),则最终左边的数一定是\(1\)$k$,右边的数一定是$k+1$\(n\),那么我们先枚举左边一段的数的个数\(k\),然后再枚举分割点\(i\)(表示第\(i\)个数的右边分割),再计算需要的能量值\(ans=\sum\limits_{j\leq i且q_j>k}a_j+\sum\limits_{j>i且q_j\leq k}a_j\),时间复杂度\(O(n^3)\)

但我们注意到分割点移动的时候,只有分割点右边一个数对答案的贡献改变,于是可以\(O(1)\)更新答案,时间复杂度\(O(n^2)\)

仔细分析可以发现,当\(k\)增加时,只有一个数,即\(k+1\)的归宿才从右边移动到左边,其他数都不变,那我们考虑这个数的归宿改变对答案的影响,可以发现,对于分割点在它左边的答案要增加它的能量值\(a_{k+1}\),以让它从右边移动到左边,而分割点在它右边的答案要减去它的能量值\(a_{k+1}\),以消除原来让它从左边移动到右边的所需要的能量。区间修改,用线段树维护答案即可。时间复杂度\(O(n\log_{2}n)\)

神奇的代码
#include <bits/stdc++.h>
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<PII> VPII;
typedef vector<LL> VL;
typedef pair<LL,LL> PLL;
typedef vector<PLL> VPLL;

template <typename T>
void read(T &x) {
    int s = 0, c = getchar();
    x = 0;
    while (isspace(c)) c = getchar();
    if (c == 45) s = 1, c = getchar();
    while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    if (s) x = -x;
}

template <typename T>
void write(T x, char c = ' ') {
    int b[40], l = 0;
    if (x < 0) putchar(45), x = -x;
    while (x > 0) b[l++] = x % 10, x /= 10;
    if (!l) putchar(48);
    while (l) putchar(b[--l] | 48);
    putchar(c);
}

const int N=2e5+8;

struct Segment_Tree{
    #define lson root<<1
    #define rson root<<1|1

    LL mark[4*N],minn[4*N];

    void build(int root,int l,int r,LL *sum){
        if (l==r){
            minn[root]=sum[l];
            mark[root]=0;
            return;
        }
        int mid=(l+r)>>1;
        build(lson,l,mid,sum);
        build(rson,mid+1,r,sum);
        minn[root]=min(minn[lson],minn[rson]);
        mark[root]=0;
    }

    void pushdown(int root){
        mark[lson]+=mark[root];
        mark[rson]+=mark[root];
        minn[lson]+=mark[root];
        minn[rson]+=mark[root];
        mark[root]=0;
    }

    void updata(int root,int l,int r,int ll,int rr,LL x){
        if (ll>rr) return;
        if (ll<=l&&r<=rr){
            minn[root]+=x;
            mark[root]+=x;
            return;
        }
        pushdown(root);
        int mid=(l+r)>>1;
        if (ll<=mid) updata(lson,l,mid,ll,rr,x);
        if (rr>mid) updata(rson,mid+1,r,ll,rr,x);
        minn[root]=min(minn[lson],minn[rson]);
    }

    LL getans(int root,int l,int r,int ll,int rr){
        if (ll<=l&&r<=rr) return minn[root];
        pushdown(root);
        int mid=(l+r)>>1;
        if (rr<mid) return getans(lson,l,mid,ll,rr);
        else if (ll>=mid) return getans(rson,mid+1,r,ll,rr);
        else return min(getans(lson,l,mid,ll,rr),getans(rson,mid+1,r,ll,rr)); 
    }

}Segment;


int n;

int pos[N];

LL sum[N],a[N];

int main(void) {
    read(n);
    for(int u,i=1;i<=n;++i){
        read(u);
        pos[u]=i;
    }
    for(int i=1;i<=n;++i){
        read(a[i]);
        sum[i]=a[i]+sum[i-1];
    }
    Segment.build(1,1,n-1,sum);
    LL ans=Segment.getans(1,1,n-1,1,n-1);
    for(int i=1;i<=n;++i){
        Segment.updata(1,1,n-1,1,pos[i]-1,a[pos[i]]);
        Segment.updata(1,1,n-1,pos[i],n-1,-a[pos[i]]);
        ans=min(ans,Segment.getans(1,1,n-1,1,n-1));
    }
    write(ans,'\n');
    return 0;
}


posted @ 2020-01-30 15:43  ~Lanly~  阅读(280)  评论(0编辑  收藏  举报