Educational Codeforces Round 20

Educational Codeforces Round 20 

A. Maximal Binary Matrix

直接从上到下从左到右填,注意只剩一个要填的位置的情况

view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 111;
bool vis[MAXN][MAXN];
void solve(){
    int n, k; cin >> n >> k;
    if(n*n<k) cout << -1 << endl;
    else{
        for(int i = 1; i <= n and k; i++) for(int j = 1; j <= n and k; j++){
            if(vis[i][j]) continue;
            if(k==1){
                if(i!=j) continue;
                vis[i][j] = true;
                k--; break;
            }
            vis[i][j] = vis[j][i] = true;
            if(i==j) k -= 1;
            else k -= 2;
            if(!k) break;
        }
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= n; j++) cout << (vis[i][j] ? 1 : 0) << ' ';
            cout << endl;
        }
    }
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("Local.in","r",stdin);
    freopen("ans.out","w",stdout);
    #endif
    solve();
    return 0;
}

B. Distances to Zero

把所有\(0\)的位置记下来然后二分找最近位置即可

view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 2e5+7;
void solve(){
    ____();
    int n;
    cin >> n;
    vector<int> vec(n);
    for(int &x : vec) cin >> x;
    vector<int> zeropos;
    for(int i = 0; i < n; i++) if(!vec[i]) zeropos.push_back(i);
    for(int i = 0; i < n; i++){
        auto p = lower_bound(zeropos.begin(),zeropos.end(),i);
        int ret = MAXN;
        if(p!=zeropos.end()) ret = *p - i;
        if(p!=zeropos.begin()){
            p--;
            ret = min(ret,i-*p);
        }
        cout << ret << ' ';
    }cout << endl;
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("Local.in","r",stdin);
    freopen("ans.out","w",stdout);
    #endif
    solve();
    return 0;
}

C. Maximal GCD

考虑枚举\(g=gcd(A)\),由于要递增,所以填的方式为\(g,2g,3g,\cdots kg+l\)

显然要满足\(g\mid \sum A_i\),找最大的满足条件的\(g\)即可

view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
typedef long long int LL;

void solve(){
    LL n, k;
    cin >> n >> k;
    if(k>1e7 or (k+1)*k/2>n) cout << -1 << endl;
    else{
        vector<LL> f;
        for(LL i = 1; i * i <= n; i++){
            if(n%i) continue;
            f.push_back(i);
            if(i!=n/i) f.push_back(n/i);
        }
        sort(f.begin(),f.end());
        LL tot = (k + 1) * k / 2;
        LL g = 1;
        for(auto d : f){
            if(tot * d > n) break;
            g = max(g,d);
        }
        vector<LL> ret;
        for(int i = 0; i < k; i++){
            ret.push_back((i+1)*g);
            n -= (i+1)*g;
        }
        ret.back() += n;
        for(auto x : ret) cout << x << ' ';
        cout << endl;
    }
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("Local.in","r",stdin);
    freopen("ans.out","w",stdout);
    #endif
    solve();
    return 0;
}

D.Magazine Ad

把所有串按空格和横杠分开,得到一些短的串,每个串的权值为长度,问题转化为把\(n\)个数分成最多\(k\)组,求权值最大的组的最小值,二分即可

view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 1e6+7;
int k;
void solve(){
    ____();
    string s;
    cin >> k;
    cin.get(); getline(cin,s);
    s.push_back('-');
    // binary search
    vector<int> pos;
    pos.push_back(-1);
    for(int i = 0; i < s.length(); i++) if(s[i]=='-' or s[i]==' ') pos.push_back(i);
    vector<int> seg;
    for(int i = 1; i < pos.size(); i++) seg.push_back(pos[i] - pos[i-1]);
    seg.back()--;
    auto check = [&](int m){
        int cnt = 0, tot = 0;
        for(int i = 0; i < seg.size(); i++){
            if(seg[i]>m) return false;
            if(tot + seg[i] <= m) tot += seg[i];
            else{
                cnt++;
                tot = seg[i];
            }
        }
        cnt++;
        return cnt <= k;
    };
    int l = 1, r = s.length();
    while(l<=r){
        int mid = (l + r) >> 1;
        if(check(mid)) r = mid - 1;
        else l = mid + 1;
    }
    cout << l << endl;
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("Local.in","r",stdin);
    freopen("ans.out","w",stdout);
    #endif
    solve();
    return 0;
}

E. Roma and Poker

考虑\(DP\)\(dp[i][j]\)表示到第\(i\)个位置赢和输的差值为\(j\)的情况下的上一个状态

转移的时候注意不能从差值的绝对值为\(k\)的状态转移过来

最后倒推回去输出答案就好了

view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 1e3+7;
const int D = 1e3+3;
const int INF = 0x3f3f3f3f;
int f[MAXN][MAXN<<1];

int n, k;
char s[MAXN];
void solve(){
    ____();
    cin >> n >> k >> s + 1;
    memset(f,0x3f,sizeof(f));
    f[0][D] = -1;
    for(int i = 1; i <= n; i++){
        if(s[i]=='L' or s[i]=='?'){                                 // lose
            for(int j = D - k + 1; j <= D + k - 1; j++){
                if(f[i-1][j]==INF) continue;
                f[i][j-1] = j;
            }
        }
        if(s[i]=='W' or s[i]=='?'){                                 // win
            for(int j = D - k + 1; j <= D + k - 1; j++){
                if(f[i-1][j]==INF) continue;
                f[i][j+1] = j;
            }
        }
        if(s[i]=='D' or s[i]=='?'){
            for(int j = D - k + 1; j <= D + k - 1; j++){
                if(f[i-1][j]==INF) continue;
                f[i][j] = j;
            }
        }
    }
    if(f[n][D+k]==INF and f[n][D-k]==INF) cout << "NO" << endl;
    else{
        int u;
        string ret;
        if(f[n][D+k]!=INF) u = D + k;
        else u = D - k;
        for(int i = n; i >= 1; i--){
            if(u - f[i][u] == 0) ret.push_back('D');
            else if(u - f[i][u] == 1) ret.push_back('W');
            else ret.push_back('L');
            u = f[i][u];
        }
        reverse(ret.begin(),ret.end());
        cout << ret << endl;
    }
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("Local.in","r",stdin);
    freopen("ans.out","w",stdout);
    #endif
    solve();
    return 0;
}

F. Coprime Subsequences

\(f(n)\)表示组合的\(gcd=n\)的方案数

\(F(n)\)表示组合的\(n\mid gcd\)的方案数

那么\(F(n) = \sum_{n\mid d}f(d)\)

根据莫比乌斯反演,\(f(n) = \sum_{n\mid d}\mu(\frac dn)F(d)\)

我们要求的答案就是\(f(1)\)

容易发现如果有\(x\)个数的因子有\(d\)那么\(F(d) = 2^x-1\)

那么我们就能很容易算出\(f(1)\)

view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MOD = 1e9+7;
const int MAXN = 1e5+7;
int n, prime[MAXN], pri_cnt, mu[MAXN], cnt[MAXN], pw[MAXN];
bool npm[MAXN];

vector<int> ds[MAXN];
void sieve(){
    mu[1] = 1;
    for(int i = 2; i < MAXN; i++){
        if(!npm[i]) prime[++pri_cnt] = i, mu[i] = -1;
        for(int j = 1; i * prime[j] < MAXN; j++){
            npm[i*prime[j]] = true;
            if(i%prime[j]==0){
                mu[i*prime[j]] = 0;
                break;
            }
            mu[i*prime[j]] = -mu[i];
        }
    }
    for(int i = 1; i < MAXN; i++) for(int j = i; j < MAXN; j += i) ds[j].push_back(i);    
    pw[0] = 1;
    for(int i = 1; i < MAXN; i++) pw[i] = pw[i-1] * 2 % MOD;
}


void solve(){
    ____();
    sieve();
    cin >> n;
    for(int i = 1; i <= n; i++){
        int x; cin >> x;
        for(int d : ds[x]) cnt[d]++;
    }
    int ret = 0;
    for(int i = 1; i < MAXN; i++) ret = (ret + mu[i] * 1ll * (pw[cnt[i]] - 1)) % MOD;
    cout << (ret + MOD) % MOD << endl;
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("Local.in","r",stdin);
    freopen("ans.out","w",stdout);
    #endif
    solve();
    return 0;
}

G. Periodic RMQ Problem

由于范围比较大,考虑离散化坐标,为了能找到最小值,需要在离散化坐标相邻的两点中间额外加入一个区间最小值的点,这个点的值可以用\(ST\)表来找,加的点的值根据两点实际坐标的距离和位置稍微分类一下就好了,然后就很好搞了

view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 6e5 + 7;
const int INF = 0x3f3f3f3f;
int n, k, A[MAXN][20];
struct Qs{ int type, l, r, x; }Q[MAXN];
struct SegTree{
    #define ls(rt) rt << 1
    #define rs(rt) rt << 1 | 1
    int minn[MAXN<<2], l[MAXN<<2], r[MAXN<<2], lazy[MAXN<<2];
    #define pushup(rt) minn[rt] = min(minn[ls(rt)],minn[rs(rt)])
    void build(int L, int R, vector<pair<int,int> > &vcc, int rt = 1){
        l[rt] = L, r[rt] = R;
        if(L + 1 == R){
            minn[rt] = vcc[L].second;
            return;
        }
        int mid = (L + R) >> 1;
        build(L,mid,vcc,ls(rt)); build(mid,R,vcc,rs(rt));
        pushup(rt);
    }
    void pushdown(int rt){
        if(!lazy[rt]) return;
        lazy[ls(rt)] = lazy[rs(rt)] = minn[ls(rt)] = minn[rs(rt)] = lazy[rt];
        lazy[rt] = 0;
    }
    void modify(int L, int R, int x, int rt = 1){
        if(L>=r[rt] or l[rt]>=R) return;
        if(L<=l[rt] and r[rt]<=R){
            lazy[rt] = minn[rt] = x;
            return;
        }
        pushdown(rt);
        modify(L,R,x,ls(rt)); modify(L,R,x,rs(rt));
        pushup(rt);
    }
    int query(int L, int R, int rt = 1){
        if(L>=r[rt] or l[rt]>=R) return INF;
        if(L<=l[rt] and r[rt]<=R) return minn[rt];
        pushdown(rt);
        return min(query(L,R,ls(rt)),query(L,R,rs(rt)));
    }
}ST;

void solve(){
    ____();
    cin >> n >> k;
    for(int i = 0; i < n; i++) cin >> A[i][0], A[i+n][0] = A[i][0];
    for(int j = 1; (1 << j) <= (n << 1); j++) for(int i = 0; i + (1 << j) - 1 < (n << 1); i++) A[i][j] = min(A[i][j-1],A[i+(1<<(j-1))][j-1]);
    auto query = [&](int l, int r){
        int d = (int)log2(r - l + 1);
        return min(A[l][d],A[r-(1<<d)+1][d]);
    };
    int q; cin >> q;
    vector<int> vec;
    for(int i = 0; i < q; i++){
        cin >> Q[i].type >> Q[i].l >> Q[i].r;
        Q[i].l--; Q[i].r--;
        if(Q[i].type==1) cin >> Q[i].x;
        vec.push_back(Q[i].l); vec.push_back(Q[i].r);
    }
    sort(vec.begin(),vec.end());
    vec.erase(unique(vec.begin(),vec.end()),vec.end());
    vector<pair<int,int> > vcc;
    for(int i = 1, lim = vec.size(); i < lim; i++){
        if(vec[i]==vec[i-1]+1) continue;
        if(vec[i]-vec[i-1]+1>=n) vcc.push_back({vec[i-1]+1,query(0,n-1)});
        else{
            int l = vec[i-1] % n, r = vec[i] % n;
            if(l>r) r += n;
            vcc.push_back({vec[i-1]+1,query(l+1,r-1)});
        }
    }
    for(int i = 0; i < (int) vec.size(); i++) vcc.push_back({vec[i],A[vec[i]%n][0]});
    sort(vcc.begin(),vcc.end());
    ST.build(0,vcc.size(),vcc);
    for(int i = 0; i < q; i++){
        int l = Q[i].l, r = Q[i].r;
        l = lower_bound(vcc.begin(),vcc.end(),make_pair(l,0)) - vcc.begin();
        r = lower_bound(vcc.begin(),vcc.end(),make_pair(r,0)) - vcc.begin();
        if(Q[i].type==1) ST.modify(l,r+1,Q[i].x);
        else printf("%d\n",ST.query(l,r+1));
    }
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("Local.in","r",stdin);
    freopen("ans.out","w",stdout);
    #endif
    solve();
    return 0;
}
posted @ 2020-08-17 18:36  _kiko  阅读(132)  评论(0编辑  收藏  举报