• 【AtCoder】AGC011


    AGC011

    A - Airport Bus

    大意:有N个人,每个人只能在([T_i,T_i +K])这段区间乘车,每辆车安排C人,问最少安排几辆车

    直接扫,遇到一个没有车的在(T_i +K)分配一辆

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <set>
    #include <cmath>
    #include <bitset>
    #include <queue>
    #define enter putchar('
    ')
    #define space putchar(' ')
    //#define ivorysi
    #define pb push_back
    #define mo 974711
    #define pii pair<int,int>
    #define mp make_pair
    #define fi first
    #define se second
    #define MAXN 500005
    #define eps 1e-12
    using namespace std;
    typedef long long int64;
    typedef double db;
    template<class T>
    void read(T &res) {
        res = 0;char c = getchar();T f = 1;
        while(c < '0' || c > '9') {
    	if(c == '-') f = -1;
    	c = getchar();
        }
        while(c >= '0' && c <= '9') {
    	res = res * 10 - '0' + c;
    	c = getchar();
        }
        res = res * f;
    }
    template<class T>
    void out(T x) {
        if(x < 0) {x = -x;putchar('-');}
        if(x >= 10) out(x / 10);
        putchar('0' + x % 10);
    }
    int N,C,K;
    int T[1000005];
    void Solve() {
        read(N);read(C);read(K);
        for(int i = 1 ; i <= N ; ++i) read(T[i]);
        sort(T + 1,T + N + 1);
        int ans = 0;
        int cnt = 0,t = 0;
        for(int i = 1 ; i <= N ; ++i) {
    	if(t < T[i] || !cnt) {
    	    ++ans;
    	    t = T[i] + K;
    	    cnt = C;
    	}
    	--cnt;
        }
        out(ans);enter;
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Solve();
    }
    

    B - Colorful Creatures

    大意:N个怪兽颜色两两不同,两个怪物如果一个大小是A颜色是B,一个大小是C(C <= 2 * A)颜色是D,新怪物可以是大小A+C,颜色是B,问最后可能是几种颜色

    直接二分找满足要求的数的位置,然后能扩到的最大体积就是从最小的数到这个数的前缀和,每次至少扩大两倍,所以只用log次

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <set>
    #include <cmath>
    #include <bitset>
    #include <queue>
    #define enter putchar('
    ')
    #define space putchar(' ')
    //#define ivorysi
    #define pb push_back
    #define mo 974711
    #define pii pair<int,int>
    #define mp make_pair
    #define fi first
    #define se second
    #define MAXN 500005
    #define eps 1e-12
    using namespace std;
    typedef long long int64;
    typedef double db;
    template<class T>
    void read(T &res) {
        res = 0;char c = getchar();T f = 1;
        while(c < '0' || c > '9') {
    	if(c == '-') f = -1;
    	c = getchar();
        }
        while(c >= '0' && c <= '9') {
    	res = res * 10 - '0' + c;
    	c = getchar();
        }
        res = res * f;
    }
    template<class T>
    void out(T x) {
        if(x < 0) {x = -x;putchar('-');}
        if(x >= 10) out(x / 10);
        putchar('0' + x % 10);
    }
    int N;
    int64 A[100005],tmp[100005],sum[1000005];
    void Solve() {
        read(N);
        for(int i = 1 ; i <= N ; ++i) {
    	read(A[i]);
    	tmp[i] = A[i];
        }
        tmp[N + 1] = 1000000001;
        sort(tmp + 1,tmp + N + 2);
        int ans = 0;
        for(int i = 1 ; i <= N ; ++i) {
    	sum[i] = sum[i - 1] + tmp[i]; 
        }
        for(int i = 1 ; i <= N ; ++i) {
    	if(2 * A[i] >= tmp[N]) {++ans;continue;}
    	int t = lower_bound(tmp + 1,tmp + N + 2,2 * A[i] + 1) - tmp - 1;
    	while(1) {
    	    if(2 * sum[t] >= tmp[N]) {++ans;break;}
    	    int p = lower_bound(tmp + 1,tmp + N + 2,sum[t] * 2 + 1) - tmp - 1;
    	    if(p == t) break;
    	    t = p;
    	}
        }
        out(ans);enter;
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Solve();
    }
    

    C - Squared Graph

    大意是给出一张图,然后建一张新图,新图的点标号是(a,b)
    如果a和c有一条边,b和d有一条边,那么(a,b)和(c,d)之间有一条边

    我们把这道题当成这道题来做,给出两张图,如果第一张图有边(a,c),第二张图有边(b,d),那么第三张图上有边(a,b)(c,d)

    如果某张图只有一个点,那么答案就是另一张图的点数

    然后我们发现对于某两个点对第一张图(a,c),第二张图(b,d)如果有一条长度为L的路径,那么第三张图(a,b)(c,d)一定可以联通
    但是我们发现我们经过的路径可以不是简单路径,也就是我们反复走一条边,那么我们只和路径长度的奇偶性有关了

    很容易想到二分图,如果两张图都是二分图且联通的话,那么第三张图联通分量的个数是2
    分别是(S_a * T_b cup T_a * S_b)(S_a * S_b cup T_a * T_b)

    而两张图都是非二分图且联通的话,任意路径的奇偶性都可以互相转化,所以整张图就是一个联通块
    那么我们求出两个图的孤立点个数(i_A,i_B),两个图的非二分图联通块个数(p_A,p_B),两个图的二分图联通块个数(q_A,q_B)
    答案就是
    (i_Ai_B + i_A(N_B - i_B) + i_B(N_A - i_A) + p_Ap_B + p_Aq_B + p_Bq_A + 2q_Aq_B)

    代码

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <set>
    #include <cmath>
    #include <bitset>
    #include <queue>
    #define enter putchar('
    ')
    #define space putchar(' ')
    //#define ivorysi
    #define pb push_back
    #define mo 974711
    #define pii pair<int,int>
    #define mp make_pair
    #define fi first
    #define se second
    #define MAXN 200005
    #define eps 1e-12
    using namespace std;
    typedef long long int64;
    typedef double db;
    template<class T>
    void read(T &res) {
        res = 0;char c = getchar();T f = 1;
        while(c < '0' || c > '9') {
    	if(c == '-') f = -1;
    	c = getchar();
        }
        while(c >= '0' && c <= '9') {
    	res = res * 10 - '0' + c;
    	c = getchar();
        }
        res = res * f;
    }
    template<class T>
    void out(T x) {
        if(x < 0) {x = -x;putchar('-');}
        if(x >= 10) out(x / 10);
        putchar('0' + x % 10);
    }
    int N,M,I,P,Q;
    struct node {
        int next,to;
    }E[MAXN * 2];
    int head[MAXN],sumE,col[MAXN];
    bool vis[MAXN];
    void dfs(int u) {
        vis[u] = 1;
        for(int i = head[u] ; i ; i = E[i].next) {
    	int v = E[i].to;
    	if(!vis[v]) {
    	    dfs(v);
    	}
        }
    }
    bool paint(int u) {
        if(!col[u]) col[u] = 2;
        for(int i = head[u] ; i; i = E[i].next) {
    	int v = E[i].to;
    	if(!col[v]) {col[v] = col[u] ^ 1;if(!paint(v)) return false;}
    	else if(col[v] == col[u]) return false;
        }
        return true;
    }
    void add(int u,int v) {
        E[++sumE].to = v;
        E[sumE].next = head[u];
        head[u] = sumE;
    }
    void Solve() {
        read(N);read(M);
        int u,v;
        for(int i = 1 ; i <= M ; ++i) {
    	read(u);read(v);
    	add(u,v);add(v,u);
        }
        for(int i = 1 ; i <= N ; ++i) {
    	if(!head[i]) ++I;
    	else if(!vis[i]){
    	    dfs(i);
    	    if(paint(i)) ++Q;
    	    else ++P;
    	}
        }
        int64 ans = 1LL * I * I + 2LL * I * (N - I);
        ans += 1LL * P * P + 2LL * P * Q + 2LL * Q * Q;
        out(ans);enter;
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Solve();
    }
    

    D - Half Reflector

    大意是n个管子排成一排,每个管子有两种状态,A状态是从某个方向进去,从原方向出来,B状态是从某个方向进去,从另一个方向出来
    球经过一个A状态的管子这个管子会立刻变成B状态,经过一个B状态的管子会立刻变成A状态

    往里面扔K个球,问最后管子的状态

    我们发现如果第一个管子是A的话,球会立刻弹出去

    否则的话
    如果第二个管子是B
    那么
    A -> B
    A A ->
    如果第二个管子是A
    A -> A
    A <- B
    B -> B
    B A ->
    也就是,每次操作后的状态只与右边第一个管子有关,并且最后一个管子一定是A
    那么操作可以考虑成,删掉第一个字符,后面的字符全部取反,然后再最后填上一个A

    然而有K次,我们发现起点移动N次之后就是循环了
    如果N次之后是
    BABABA...那么这个形态不会变

    如果N次之后是
    ABABAB...

    那么之后的形态就是
    BBABAB...
    ABABAB...
    这样的循环了

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <set>
    #include <cmath>
    #include <bitset>
    #include <queue>
    #define enter putchar('
    ')
    #define space putchar(' ')
    //#define ivorysi
    #define pb push_back
    #define mo 974711
    #define pii pair<int,int>
    #define mp make_pair
    #define fi first
    #define se second
    #define MAXN 200005
    #define eps 1e-12
    using namespace std;
    typedef long long int64;
    typedef double db;
    template<class T>
    void read(T &res) {
        res = 0;char c = getchar();T f = 1;
        while(c < '0' || c > '9') {
    	if(c == '-') f = -1;
    	c = getchar();
        }
        while(c >= '0' && c <= '9') {
    	res = res * 10 - '0' + c;
    	c = getchar();
        }
        res = res * f;
    }
    template<class T>
    void out(T x) {
        if(x < 0) {x = -x;putchar('-');}
        if(x >= 10) out(x / 10);
        putchar('0' + x % 10);
    }
    char s[MAXN];
    int N,K,p = 1,num[MAXN],cnt,st;
    void Solve() {
        read(N);read(K);
        scanf("%s",s + 1);
        for(int i = 1 ; i <= N ; ++i) num[i] = s[i] - 'A';
        st = num[1];
        while(K--) {
    	if(st == 0) {st ^= 1;num[p] ^= 1;}
    	else {
    	    ++p;++cnt;
    	    st = num[p];
    	    st ^= (cnt & 1);
    	}
    	if(p > N) break;
        }
        if(p <= N) {
    	for(int i = p ; i <= N ; ++i) putchar('A' + (num[i] ^ (cnt & 1)));
    	int t = N - (N - p + 1),c = (cnt - 1) & 1;
    	while(t--) {
    	    putchar('A' + c);
    	    c ^= 1;
    	}
        }
        else {
    	if((cnt - 1) & 1) {
    	    for(int i = 1 ; i <= N ; ++i) putchar('A' + (i & 1));
    	}
    	else {
    	    putchar('A' + (K & 1));
    	    for(int i = 1 ; i < N ; ++i) putchar('A' + (i & 1));
    	}
        }
        enter;
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Solve();
    }
    

    E - Increasing Numbers

    我们发现一个非下降的数字一定可以用不超过九个1111111111...1111表示

    那么我们可以得到这样的一个式子,假如我们用了k个数,那么最多的话可以是这样的
    (N = sum_{i = 1}^{9k} (10^{r_i} - 1) / 9)
    (9N + 9k = sum_{i = 1}^{9k} 10^{r_{i}})

    我们只要每次计算出9N + 9 ,9N + 18...,然后看看十进制下每一位的数字和有没有超过9k,直接加的话最坏情况是一次操作(O(L))的,但是大家应该都有种直觉总的操作就是(O(L))的……就是势能分析啦,不太会证,就是一次长的进位过后之后不会再进位了。。。

    复杂度(O(lg N))

    代码

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <set>
    #include <cmath>
    #include <bitset>
    #include <queue>
    #define enter putchar('
    ')
    #define space putchar(' ')
    //#define ivorysi
    #define pb push_back
    #define mo 974711
    #define pii pair<int,int>
    #define mp make_pair
    #define fi first
    #define se second
    #define MAXN 200005
    #define eps 1e-12
    using namespace std;
    typedef long long int64;
    typedef double db;
    template<class T>
    void read(T &res) {
        res = 0;char c = getchar();T f = 1;
        while(c < '0' || c > '9') {
    	if(c == '-') f = -1;
    	c = getchar();
        }
        while(c >= '0' && c <= '9') {
    	res = res * 10 - '0' + c;
    	c = getchar();
        }
        res = res * f;
    }
    template<class T>
    void out(T x) {
        if(x < 0) {x = -x;putchar('-');}
        if(x >= 10) out(x / 10);
        putchar('0' + x % 10);
    }
    struct Bignum {
        vector<int> v;
        int sum;
        Bignum operator = (string s) {
    	v.clear();
    	sum = 0;
    	for(int i = s.length() - 1 ; i >= 0 ; --i) {
    	    v.pb(s[i] - '0');
    	    sum += s[i] - '0';
    	}
    	return *this;
        }
        friend Bignum operator * (const Bignum &a,const int b) {
    	int s = a.v.size();
    	Bignum c;c.v.clear();
    	for(int i = 0 ; i <= s ; ++i) c.v.pb(0);
    	int g = 0;
    	for(int i = 0 ; i < s ; ++i) {
    	    int x = a.v[i] * b + g;
    	    c.v[i] = x % 10;
    	    g = x / 10;
    	}
    	if(g) c.v[s] = g;
    	for(int i = s ; i > 0 ; --i) {
    	    if(c.v[i] == 0) c.v.pop_back();
    	    else break;
    	}
    	c.sum = 0;s = c.v.size();
    	for(int i = 0 ; i < s ; ++i) c.sum += c.v[i];
    	return c;
        }
    }A;
    string s;
    void Solve() {
        cin>>s;
        A = s;
        A = A * 9;
        int ans = 0;
        while(1) {
    	int s = A.v.size();
    	int g = 9;
    	for(int i = 0 ; i < s ; ++i) {
    	    if(!g) break;
    	    A.sum -= A.v[i];
    	    int x = A.v[i] + g;
    	    A.v[i] = x % 10;
    	    A.sum += A.v[i];
    	    g = x / 10;
    	}
    	if(g) A.v.pb(g),A.sum += g;
    	++ans;
    	if(ans * 9 >= A.sum) break;
        }
        out(ans);enter;
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Solve();
    }
    

    F - Train Service Planning

    如果认为从0到N每一站休息时间是(q_0,q_1,q_2...q_{N- 1})

    然后我们认为从N到0每一站休息时间是(p_0,p_1,p_2...p_{N - 1})

    ((sum_{i = 0}^{s - 1} q_i + sum_{i = 0}^{s - 1}A_{i},sum_{i = 0}^{s - 1} q_i + sum_{i = 0}^{s}A_{i}))

    这是从第s - 1站走到第s站的时间段

    ((N - sum_{i = 0}^{s - 1} p_i - sum_{i = 0}^{s}A_{i},N - sum_{i = 0}^{s - 1} p_i - sum_{i = 0}^{s - 1}A_{i}))

    我们要这两个区间没有交集

    由于取模k意义下,最后只要满足

    (sum_{i = 0}^{s - 1}p_{i} + q_i otin (-2sum_{i = 0}^{s}A_{i},-2sum_{i = 0}^{s - 1}A{i}))

    最后就变成,对于每个单行道,我们要求坐标取模的值在某个区间内

    (dpL[i])是i的时候在(L[i])的位置上之后还要走多远,(dpR[i])同理

    从后往前更新,每次找(L[i])不在区间([L[j],R[j]])的一个最小的j

    然后用(dpL[j])(dpR[j])更新

    线段树优化

    然后可以当答案的(dpL[i])要求(L[i])(1-i)的区间内,可以用线段树求

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int,int>
    #define mp make_pair
    #define pb push_back
    #define space putchar(' ')
    #define enter putchar('
    ')
    #define eps 1e-10
    #define MAXN 100005
    //#define ivorysi
    using namespace std;
    typedef long long int64;
    typedef unsigned int u32;
    typedef double db;
    template<class T>
    void read(T &res) {
        res = 0;T f = 1;char c = getchar();
        while(c < '0' || c > '9') {
        	if(c == '-') f = -1;
        	c = getchar();
        }
        while(c >= '0' && c <= '9') {
        	res = res * 10 +c - '0';
        	c = getchar();
        }
        res *= f;
    }
    template<class T>
    void out(T x) {
        if(x < 0) {x = -x;putchar('-');}
        if(x >= 10) {
        	out(x / 10);
        }
        putchar('0' + x % 10);
    }
    
    int N;
    int64 K,A[MAXN],sum[MAXN];
    int B[MAXN],tot;
    int64 L[MAXN],R[MAXN],dpL[MAXN],dpR[MAXN],val[MAXN];
    struct node {
        int l,r;
        int mx,lz;
    }tr[MAXN * 4];
    int id;
    void update(int u) {
        if(!id) tr[u].mx = min(tr[u << 1].mx,tr[u << 1 | 1].mx);
        else tr[u].mx = max(tr[u << 1].mx,tr[u << 1 | 1].mx);
    }
    void addlz(int u,int v) {
        tr[u].lz = v;
        tr[u].mx = v;
    }
    void pushdown(int u) {
        if(tr[u].lz) {
            addlz(u << 1,tr[u].lz);
            addlz(u << 1 | 1,tr[u].lz);
            tr[u].lz = 0;
        }
    }
    void build(int u,int l,int r,int v) {
        tr[u].l = l;tr[u].r = r;tr[u].lz = 0;
        if(l == r) {
            tr[u].mx = v;
            return;
        }
        int mid = (l + r) >> 1;
        build(u << 1,l,mid,v);
        build(u << 1 | 1,mid + 1,r,v);
        update(u);
    }
    void cover(int u,int l,int r,int v) {
        if(l > r) return;
        if(tr[u].l == l && tr[u].r == r) {
            addlz(u,v);
            return;
        }
        pushdown(u);
        int mid = (tr[u].l + tr[u].r) >> 1;
        if(r <= mid) cover(u << 1,l,r,v);
        else if(l > mid) cover(u << 1 | 1,l,r,v);
        else {cover(u << 1,l,mid,v);cover(u << 1 | 1,mid + 1,r,v);}
        update(u);
    }
    int query(int u,int l,int r) {
        if(l > r) return N + 1;
        if(tr[u].l == l && tr[u].r == r) return tr[u].mx;
        pushdown(u);
        int mid = (tr[u].l + tr[u].r) >> 1;
        if(r <= mid) return query(u << 1,l,r);
        else if(l > mid) return query(u << 1 | 1,l,r);
        else {
            if(!id) return min(query(u << 1,l,mid),query(u << 1 | 1,mid + 1,r));
            else return max(query(u << 1,l,mid),query(u << 1 | 1,mid + 1,r));
        }
    }
    int64 dist(int64 A,int64 B) {
        if(B >= A) return B - A;
        else return K - (A - B);
    }
    void Solve() {
        read(N);read(K);
        for(int i = 1 ; i <= N ; ++i) {
            read(A[i]);read(B[i]);
            sum[i] = sum[i - 1] + A[i];
            if(B[i] == 1) {
                if(2 * A[i] > K) {puts("-1");return;}
                L[i] = (-2 * sum[i - 1] % K + K) % K;
                R[i] = (-2 * sum[i] % K + K) % K;
                val[++tot] = L[i];val[++tot] = R[i];
            }
        }
    
        sort(val + 1,val + tot + 1);
        tot = unique(val + 1,val + tot + 1) - val - 1;
        id = 0;
        build(1,1,tot,N + 1);
        for(int i = N ; i >= 1 ; --i) {
            if(B[i] == 1) {
                int l = lower_bound(val + 1,val + tot + 1,L[i]) - val;
                int r = lower_bound(val + 1,val + tot + 1,R[i]) - val;
                int t = query(1,l,l);
                if(t == N + 1) dpL[i] = 0;
                else dpL[i] = min(dpL[t] + dist(L[i],L[t]),dpR[t] + dist(L[i],R[t]));
                t = query(1,r,r);
                if(t == N + 1) dpR[i] = 0;
                else dpR[i] = min(dpR[t] + dist(R[i],R[t]),dpL[t] + dist(R[i],L[t]));
                if(l <= r) {cover(1,1,l - 1,i);cover(1,r + 1,tot,i);}
                else {cover(1,r + 1,l - 1,i);}
            }
        }
        id = 1;
        build(1,1,tot,0);
        int64 ans = 1e18;
        for(int i = 1 ; i <= N ; ++i) {
            if(B[i] == 1) {
                int l = lower_bound(val + 1,val + tot + 1,L[i]) - val;
                int r = lower_bound(val + 1,val + tot + 1,R[i]) - val;
                int t = query(1,l,l);
                if(t == 0) ans = min(ans,dpL[i]);
                t = query(1,r,r);
                if(t == 0) ans = min(ans,dpR[i]);
                if(l <= r) {cover(1,1,l - 1,i);cover(1,r + 1,tot,i);}
                else {cover(1,r + 1,l - 1,i);}
            }
        }
        ans += 2 * sum[N];
        out(ans);enter;
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Solve();
    }
    
  • 相关阅读:
    max_input_vars 的影响
    php中定义网站根目录的常用方法
    phpstorm编辑器智能提示框架代码
    XunSearch(讯搜)的使用教程步骤
    xunsearch增量索引改进版
    在Windows7上安装coreseek3.2同时在PHP下简单实现步骤
    Linux下PHP+MySQL+CoreSeek中文检索引擎配置
    用js实现导航菜单点击切换选中时高亮状态
    jquery ajax POST 例子详解
    CentOS如何挂载硬盘
  • 原文地址:https://www.cnblogs.com/ivorysi/p/10803917.html
Copyright © 2020-2023  润新知