Educational Codeforces Round 24

Educational Codeforces Round 24 

A.Diplomas and Certificates

\(a+k\cdot a\le \lfloor \frac n2\rfloor\rightarrow a\le \lfloor \frac{\lfloor \frac n2\rfloor}{k+1}\rfloor\)

就没了

view code
#pragma GCC optimize("O3")
#pragma GCC optimize("Ofast,no-stack-protector")
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define LL long long int
#define vi vector<int>
#define vl vector<LL>
#define all(V) V.begin(),V.end()
#define sci(x) scanf("%d",&x)
#define scl(x) scanf("%I64d",&x)
#define pii pair<int,int>
#define pll pair<LL,LL>
#define cmax(a,b) ((a) = (a) > (b) ? (a) : (b))
#define cmin(a,b) ((a) = (a) < (b) ? (a) : (b))
#define debug(x)  cerr << #x << " = " << x << endl
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
template <typename T> void operator << (vector<T> &__container, T x){ __container.push_back(x); }
template <typename T> ostream& operator << (ostream &out, vector<T> &__container){ for(T _ : __container) out << _ << ' '; }
const int MAXN = 2e5+7;

void solve(){
    LL n, k;
    scl(n), scl(k);
    LL a = n / 2 / (k + 1);
    cout << a << ' ' << k * a << ' ' << n - (k + 1) * a << endl;
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("Local.in","r",stdin);
    freopen("ans.out","w",stdout);
    #endif
    solve();
    return 0;
}

B. Permutation Game

就模拟数数即可,用一个\(set\)记一下用过的数

view code
#pragma GCC optimize("O3")
#pragma GCC optimize("Ofast,no-stack-protector")
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define LL long long int
#define vi vector<int>
#define vl vector<LL>
#define all(V) V.begin(),V.end()
#define sci(x) scanf("%d",&x)
#define scl(x) scanf("%I64d",&x)
#define pii pair<int,int>
#define pll pair<LL,LL>
#define cmax(a,b) ((a) = (a) > (b) ? (a) : (b))
#define cmin(a,b) ((a) = (a) < (b) ? (a) : (b))
#define debug(x)  cerr << #x << " = " << x << endl
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
template <typename T> void operator << (vector<T> &__container, T x){ __container.push_back(x); }
template <typename T> ostream& operator << (ostream &out, vector<T> &__container){ for(T _ : __container) out << _ << ' '; }
const int MAXN = 2e5+7;

void solve(){
    int n, m;
    sci(n); sci(m);
    vi A(m);
    for(int &x : A) sci(x), x--;
    vi ret(n,-1);
    set<int> S;
    for(int i = 1; i <= n; i++) S.insert(i);
    for(int i = 1; i < m; i++){
        int pre = A[i-1], now = A[i];
        int delta = (now - pre + n) % n;
        if(!delta) delta += n;
        if(ret[A[i-1]]!=-1 and ret[A[i-1]]!=delta){
            cout << -1 << endl;
            return;
        }
        if(ret[A[i-1]]!=-1) continue;
        if(!S.count(delta)){
            cout << -1 << endl;
            return;
        }
        ret[A[i-1]] = delta;
        S.erase(delta);
    }
    for(int i = 0; i < n; i++){
        if(ret[i]!=-1) cout << ret[i] << ' ';
        else cout << *S.begin() << ' ', S.erase(S.begin());
    }
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("Local.in","r",stdin);
    freopen("ans.out","w",stdout);
    #endif
    solve();
    return 0;
}

C. Sofa Thief

每个点对记一下上下左右四个方向的最值,然后枚举每个点对,二分一下找四个方向上有多少个就好了

view code
#pragma GCC optimize("O3")
#pragma GCC optimize("Ofast,no-stack-protector")
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define LL long long int
#define vi vector<int>
#define vl vector<LL>
#define all(V) V.begin(),V.end()
#define sci(x) scanf("%d",&x)
#define scl(x) scanf("%I64d",&x)
#define pii pair<int,int>
#define pll pair<LL,LL>
#define cmax(a,b) ((a) = (a) > (b) ? (a) : (b))
#define cmin(a,b) ((a) = (a) < (b) ? (a) : (b))
#define debug(x)  cerr << #x << " = " << x << endl
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
template <typename T> void operator << (vector<T> &__container, T x){ __container.push_back(x); }
template <typename T> ostream& operator << (ostream &out, vector<T> &__container){ for(T _ : __container) out << _ << ' '; }
const int MAXN = 2e5+7;

void solve(){
    int d, n, m;
    sci(d); sci(n); sci(m);
    vector<pair<pii,pii> > vec(d);
    for(auto &x : vec) sci(x.first.first), sci(x.first.second), sci(x.second.first), sci(x.second.second);
    int c[4];
    for(int i = 0; i < 4; i++) sci(c[i]);
    vector<vi> A(4,vi());
    for(auto &x : vec){
        A[0] << min(x.first.first,x.second.first);
        A[1] << max(x.first.first,x.second.first);
        A[2] << min(x.first.second,x.second.second);
        A[3] << max(x.first.second,x.second.second);
    }
    for(int i = 0; i < 4; i++) sort(all(A[i]));
    for(int i = 0; i < d; i++){
        auto p = vec[i];
        int x1 = p.first.first, y1 = p.first.second, x2 = p.second.first, y2 = p.second.second;
        int num[4] = {0,0,0,0};
        num[0] = lower_bound(all(A[0]),max(x1,x2)) - A[0].begin() - (x1!=x2 ? 1 : 0);
        num[2] = lower_bound(all(A[2]),max(y1,y2)) - A[2].begin() - (y1!=y2 ? 1 : 0);
        num[1] = A[1].end() - upper_bound(all(A[1]),min(x1,x2)) - (x1!=x2 ? 1 : 0);
        num[3] = A[3].end() - upper_bound(all(A[3]),min(y1,y2)) - (y1!=y2 ? 1 : 0);
        if(num[0]==c[0] and num[1]==c[1] and num[2]==c[2] and num[3]==c[3]){
            cout << i + 1 << endl;
            return;
        }
    }
    cout << -1 << endl;
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("Local.in","r",stdin);
    freopen("ans.out","w",stdout);
    #endif
    solve();
    return 0;
}

D. Multicolored Cars

假设一开始\(Bob\)有除了\(Alice\)选的数之外的所有数,然后遍历一遍,如果某时刻\(Alice\)的值比其他的某个值大了,那那个值就没有用了,否则继续维护出现的次数

view code
#pragma GCC optimize("O3")
#pragma GCC optimize("Ofast,no-stack-protector")
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define LL long long int
#define vi vector<int>
#define vl vector<LL>
#define all(V) V.begin(),V.end()
#define sci(x) scanf("%d",&x)
#define scl(x) scanf("%I64d",&x)
#define pii pair<int,int>
#define pll pair<LL,LL>
#define cmax(a,b) ((a) = (a) > (b) ? (a) : (b))
#define cmin(a,b) ((a) = (a) < (b) ? (a) : (b))
#define debug(x)  cerr << #x << " = " << x << endl
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
template <typename T> void operator << (vector<T> &__container, T x){ __container.push_back(x); }
template <typename T> ostream& operator << (ostream &out, vector<T> &__container){ for(T _ : __container) out << _ << ' '; }
const int MAXN = 2e5+7;
int cnt[MAXN<<3];
void solve(){
    int n, c; sci(n); sci(c);
    vi A(n);
    for(int &x : A) sci(x);
    int alice = 0;
    for(int i = 0; i < n; i++){
        if(A[i]==c) alice++;
        else{
            if(cnt[A[i]]<alice) continue;
            else cnt[A[i]]++;
        }
    }
    for(int i = 1; i <= 1e6; i++) if(i!=c and cnt[i]>=alice){
        cout << i << endl;
        return;
    }
    cout << -1 << endl;
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("Local.in","r",stdin);
    freopen("ans.out","w",stdout);
    #endif
    solve();
    return 0;
}

E. Card Game Again

\(k\)分解质因子

然后双指针,枚举左端点,要求左端点和右端点区间中的各因子数的和要大于\(k\)中的因子数

注意特判\(0\)

view code
#pragma GCC optimize("O3")
#pragma GCC optimize("Ofast,no-stack-protector")
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define LL long long int
#define vi vector<int>
#define vl vector<LL>
#define all(V) V.begin(),V.end()
#define sci(x) scanf("%d",&x)
#define scl(x) scanf("%I64d",&x)
#define pii pair<int,int>
#define pll pair<LL,LL>
#define cmax(a,b) ((a) = (a) > (b) ? (a) : (b))
#define cmin(a,b) ((a) = (a) < (b) ? (a) : (b))
#define debug(x)  cerr << #x << " = " << x << endl
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
template <typename T> void operator << (vector<T> &__container, T x){ __container.push_back(x); }
template <typename T> ostream& operator << (ostream &out, vector<T> &__container){ for(T _ : __container) out << _ << ' '; }
const int MAXN = 2e5+7;

void solve(){
    int n, k;
    sci(n); sci(k);
    vi A(n);
    for(int &x : A) sci(x);
    if(k==1){
        cout << 1ll * n * (n + 1) / 2 << endl;
        return;
    }
    vector<pii> f;
    for(int i = 2; i * i <= k; i++){
        if(k%i) continue;
        f << pii(i,0);
        while(k%i==0) k/=i, f.back().second++;
    }
    if(k!=1) f << pii(k,1);
    LL ret = 0;
    auto check = [&](){ for(auto p : f) if(p.second>0) return false; return true; };
    auto go_next = [&](int &ptr){
        int x = A[++ptr];
        for(auto &p : f) while(x%p.first==0) x/=p.first, p.second--;
    };
    for(int i = 0, ptr = -1; i < n; i++){
        while(ptr<n-1 and !check()) go_next(ptr);
        if(ptr==n-1 and !check()) break;
        ret += n - ptr;
        for(auto &p : f) while(A[i]%p.first==0) A[i]/=p.first, p.second++;
    }
    cout << ret << endl;
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("Local.in","r",stdin);
    freopen("ans.out","w",stdout);
    #endif
    solve();
    return 0;
}

F. Level Generation

考虑一开始是一个树的结构,这样最多有\(n-1\)个桥,考虑构造一个\(m\)个点连成一条链,然后剩下的点之间随意连边,这样可以保证总边数最多,显然是可以二分的

view code
#pragma GCC optimize("O3")
#pragma GCC optimize("Ofast,no-stack-protector")
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define endl "\n"
#define LL long long int
#define vi vector<int>
#define vl vector<LL>
#define all(V) V.begin(),V.end()
#define sci(x) scanf("%d",&x)
#define scl(x) scanf("%I64d",&x)
#define pii pair<int,int>
#define pll pair<LL,LL>
#define cmax(a,b) ((a) = (a) > (b) ? (a) : (b))
#define cmin(a,b) ((a) = (a) < (b) ? (a) : (b))
#define debug(x)  cerr << #x << " = " << x << endl
#ifndef ONLINE_JUDGE
#define cout cerr
#endif
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
template <typename T> void operator << (vector<T> &__container, T x){ __container.push_back(x); }
template <typename T> ostream& operator << (ostream &out, vector<T> &__container){ for(T _ : __container) out << _ << ' '; }
const int MAXN = 2e5+7;
LL go(){
    int n; sci(n);
    if(n==1) return 0;
    LL l = 1, r = n - 1;
    while(l<=r){
        LL mid = (l + r) >> 1;
        LL lft = n - mid;
        LL comp = lft * (lft - 1) / 2;
        if(comp>=mid) l = mid + 1;
        else r = mid - 1;
    }
    return max(r << 1, (r + 1) + (n - r - 1)*(n - r - 2) / 2);
}
void solve(){
    int q; sci(q);
    for(int i = 1; i <= q; i++) printf("%I64d\n",go());
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("Local.in","r",stdin);
    freopen("ans.out","w",stdout);
    #endif
    solve();
    return 0;
}

G. Four Melodies

能想到费用流

考虑最朴素的建图方式:

每个点拆成\(in_i,out_i\)两个点

  • \(in_i\)\(out_i\)连容量为\(1\),费用为\(-1\)的边
  • 对于每个\(i\)向所有在它之后的与之绝对值相差\(1\)的点\(j\)\(out_i\rightarrow in_j\)容量为\(1\),费用为\(0\)的边
  • 对于每个\(i\)向所有在它之后的模\(7\)同余的点\(j\)\(out_i\rightarrow in_j\)容量为\(1\),费用为\(0\)的边

然后跑最小费用最大流就好了,但是可以发现这样建图,边数是\(n^2\)

考虑优化建图

边数变多是因为一个点往他后面的所有的可以连的点都连边了,而实际上可以建立一些中间点使得前面的点通过中间点再到后面的点

这里考虑把每个节点拆成\(4\)个点:\(in_{i1}\)\(in_{i2}\)\(sk_i\)\(out_i\)

  • \(sk_i\rightarrow out_i\)容量为\(1\)费用为\(0\),用于限流

  • \(in_{i1}\rightarrow sk_i\),容量为\(1\),费用为\(-1\)

  • \(in_{i2}\rightarrow sk_i\),容量为\(1\),费用为\(-1\)

  • 找到下一个和\(a_i\)相同的\(a_j\)\(in_{i1}\rightarrow in_{j1}\),容量为\(INF\),费用为\(0\)

  • 找到下一个和\(a_i\)\(7\)同余的\(a_j\)\(in_{i2}\rightarrow in_{j2}\),容量为\(INF\),费用为\(0\)

  • 下一个与\(a_i\)差值为\(1\)\(a_j\),连\(out_i\rightarrow in_{j1}\),容量为\(1\),费用为\(0\)

  • 下一个与\(a_i\)差值为\(-1\)\(a_j\),连\(out_i\rightarrow in_{j1}\),容量为\(1\),费用为\(0\)

  • 下一个与\(a_i\)\(7\)同余的\(a_j\),连\(out_i\rightarrow in_{j2}\),容量为\(1\),费用为\(0\)

其他的源汇点的连边就和朴素的建图方式一样了

这样边数就是\(O(n)\)的了

view code
#pragma GCC optimize("O3")
#pragma GCC optimize("Ofast,no-stack-protector")
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define endl "\n"
#define LL long long int
#define vi vector<int>
#define vl vector<LL>
#define all(V) V.begin(),V.end()
#define sci(x) scanf("%d",&x)
#define scl(x) scanf("%I64d",&x)
#define pii pair<int,int>
#define pll pair<LL,LL>
#ifndef ONLINE_JUDGE
#define cout cerr
#endif
#define cmax(a,b) ((a) = (a) > (b) ? (a) : (b))
#define cmin(a,b) ((a) = (a) < (b) ? (a) : (b))
#define debug(x)  cerr << #x << " = " << x << endl
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
template <typename T> void operator << (vector<T> &__container, T x){ __container.push_back(x); }
template <typename T> ostream& operator << (ostream &out, vector<T> &__container){ for(T _ : __container) out << _ << ' '; }
const int MAXN = 2e4+7;
#define S 0
#define T MAXN - 1
struct EDGE{
    int to,cap,fee,rev;
    EDGE(){}
    EDGE(int _to, int _cap, int _fee, int _rev){
        to = _to; cap = _cap;
        fee = _fee; rev = _rev;
    }
};
int pre[MAXN], preid[MAXN], dist[MAXN], flow[MAXN];
bool vis[MAXN];
vector<EDGE> G[MAXN];
void ADDEDGE(int u, int v, int cap, int fee){
    G[u].emplace_back(EDGE(v,cap,fee,(int)G[v].size()));
    G[v].emplace_back(EDGE(u,0,-fee,(int)G[u].size()-1));
}
bool spfa(){
    memset(dist,0x3f,sizeof(dist));
    dist[S] = 0;
    flow[S] = INF;
    memset(vis,0,sizeof(vis));
    queue<int> que;
    que.push(S);
    while(!que.empty()){
        int u = que.front();
        que.pop();
        vis[u] = 0;
        for(int i = 0; i < (int)G[u].size(); i++){
            auto e = G[u][i];
            if(!e.cap or dist[e.to]<=dist[u]+e.fee) continue;
            dist[e.to] = dist[u] + e.fee;
            flow[e.to] = min(e.cap,flow[u]);
            pre[e.to] = u; preid[e.to] = i;
            if(!vis[e.to]){
                vis[e.to] = 1;
                que.push(e.to);
            }
        }
    }
    return dist[T]!=INF;
}
int mcmf(){
    int cost = 0;
    while(spfa()){
        int u = T;
        cost += dist[T] * flow[T];
        while(u!=S){
            int p = pre[u], id = preid[u];
            G[p][id].cap -= flow[T];
            G[u][G[p][id].rev].cap += flow[T];
            u = pre[u];
        }
    }
    return cost;
}
const int K = MAXN - 2, P = MAXN - 3;
void solve(){
    int n; sci(n);
    vi A(n); for(int &x : A) sci(x);
    ADDEDGE(S,K,4,0);
    for(int i = 0; i < n; i++) ADDEDGE(K,i+1+2*n,1,0);
    for(int i = 0; i < n; i++) ADDEDGE(i+1+3*n,P,1,0);
    ADDEDGE(P,T,4,0);
    for(int i = 0; i < n; i++){
        ADDEDGE(i+1,i+1+2*n,1,0);
        ADDEDGE(i+1+n,i+1+2*n,1,0);
        ADDEDGE(i+1+2*n,i+1+3*n,1,-1);
    }
    for(int i = 0; i < n; i++){
        bool n1 = false, p1 = false, emod = false;
        for(int j = i + 1; j < n; j++){
            if(A[j]-A[i]==-1 and !n1){
                n1 = true;
                ADDEDGE(i+1+3*n,j+1,1,0);
            }
            if(A[j]-A[i]==1 and !p1){
                p1 = true;
                ADDEDGE(i+1+3*n,j+1,1,0);
            }
            if(A[i]%7==A[j]%7 and !emod){
                emod = true;
                ADDEDGE(i+1+3*n,j+1+n,1,0);
            }
        }
    }
    for(int i = 0; i < n; i++){
        bool eq = false, em = false;
        for(int j = i + 1; j < n; j++){
            if(A[j] == A[i] and !eq){
                eq = true;
                ADDEDGE(i+1,j+1,INF,0);
            }
            if(A[i]%7==A[j]%7 and !em){
                em = true;
                ADDEDGE(i+1+n,j+1+n,INF,0);
            }
        }
    }
    
    cout << -mcmf() << endl;
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("Local.in","r",stdin);
    freopen("ans.out","w",stdout);
    #endif
    solve();
    return 0;
}
posted @ 2020-08-22 15:34  _kiko  阅读(91)  评论(0编辑  收藏  举报