zoukankan      html  css  js  c++  java
  • 【AtCoder】AGC028 (A-E)题解

    A - Two Abbreviations

    如果有最小答案的话这个答案一定是N和M的lcm
    我们考虑一下什么情况下
    (k frac{L}{N} = h frac{L}{M})(k,g)互质
    显然是在(k = frac{N}{gcd(N,M)},h = frac{M}{gcd(N,M)})的时候成立

    我们只要不断枚举(k * i,h * 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 enter putchar('
    ')
        #define space putchar(' ')
        //#define ivorysi
        #define MAXN 100005
        typedef long long int64;
        using namespace std;
        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 + 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);
        }
        int64 N,M;
        char S[MAXN],T[MAXN];
        int64 gcd(int64 a,int64 b) {
        	return b == 0 ? a : gcd(b,a % b);
        }
        int64 lcm(int64 a,int64 b) {
        	return a * b / gcd(a,b);
        }
        void Solve() {
            read(N);read(M);
        	scanf("%s",S + 1);scanf("%s",T + 1);
        	int64 c = lcm(N,M);
        	int64 a = c / M,b = c / N;
        	for(int i = 0 ; i <= N ; ++i) {
        		if(i * a + 1 > N || i * b + 1 > M) break;
        		if(S[i * a + 1] != T[i * b + 1]) {puts("-1");return;}
        	}
        	out(c);enter;
        }
        int main() {
        #ifdef ivorysi
        	freopen("f1.in","r",stdin);
        #endif
        	Solve();
        	return 0;
        }
    

    B - Removing Blocks

    我计数计的挺麻烦的

    我是对于每一段统计一下这一段会被哪些序列统计到

    显然对于长度为K的一个段,除掉最靠前的一段和最靠后的一段,中间的每个段,如果这一段被取了,那么这个操作序列必定包含一个子序列,就是这一段两侧被提前取了,中间是K个数的任意排列

    然后我们对于每个长度特殊处理最前一段和最后一段(因为他们的端点只有一个),对于中间的序列计算排列个数,而中间序列的代价总和可以通过前缀和的前缀和快速算出来

    代码

        #include <bits/stdc++.h>
        #define fi first
        #define se second
        #define pii pair<int,int>
        #define mp make_pair
        #define pb push_back
        #define enter putchar('
    ')
        #define space putchar(' ')
        //#define ivorysi
        #define MAXN 100005
        typedef long long int64;
        using namespace std;
        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 + 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);
        }
        const int MOD = 1000000007;
        int N,A[MAXN],fac[MAXN],invfac[MAXN],inv[MAXN],sum[MAXN],sum_of_sum[MAXN];
        int inc(int a,int b) {
        	return a + b >= MOD ? a + b - MOD : a + b;
        }
        int mul(int a,int b) {
        	return 1LL * a * b % MOD;
        }
        void update(int &x,int y) {
        	x = inc(x,y);
        }
        int C(int n,int m) {
        	if(n < m) return 0;
        	return mul(fac[n],mul(invfac[m],invfac[n - m]));
        }
        void Solve() {
            read(N);
        	for(int i = 1 ; i <= N ; ++i) {
        		read(A[i]);
        		sum[i] = inc(sum[i - 1],A[i]);
        		sum_of_sum[i] = inc(sum_of_sum[i - 1],sum[i]);
        	}
        	inv[1] = 1;
        	for(int i = 2 ; i <= N ; ++i) {
        		inv[i] = mul(inv[MOD % i],MOD - MOD / i);
        	}
        	fac[0] = invfac[0] = 1;
        	for(int i = 1 ; i <= N ; ++i) {
        		fac[i] = mul(fac[i - 1],i);
        		invfac[i] = mul(invfac[i - 1],inv[i]);
        	}
        	int ans = 0;
        	for(int i = 1 ; i <= N ; ++i) {
        		if(i == N) update(ans,mul(sum[N],fac[N]));
        		else {
        			update(ans,mul(inc(sum[i],inc(sum[N],MOD - sum[N - i])),mul(mul(fac[i],C(N,i + 1)),fac[N - i - 1])));
        			if(i < N - 1) {
        				int t = inc(sum_of_sum[N - 1],MOD - sum_of_sum[i]);
        				update(t,MOD - sum_of_sum[N - i - 1]);
        				update(ans,mul(t,mul(mul(mul(2,fac[i]),C(N,i + 2)),fac[N - i - 2])));
        			}
        		}
        	}
        	out(ans);enter;
        }
        int main() {
        #ifdef ivorysi
        	freopen("f1.in","r",stdin);
        #endif
        	Solve();
        	return 0;
        }
    

    C - Min Cost Cycle

    显然如果最优的话,答案至少为这2×N个数里前N小的数的和
    我们把所有前N小的数标出来,称为1,后N个数称为0
    那么一个点有4种情况 01 10 00 11
    后两种个数相同

    如果我们有00(我们一定会有相同个数的11)的话,那么一定可行,为什么,因为我们把01首尾相接成一个01,把10首尾相接成一个10,然后01 00 10 11就可以了

    如果我们只有10或只有01,也一定可行

    唯一取不到这个解的是有10,并且有01,而且不存在00
    那么这个时候我们枚举两个1相撞时1的值(如果这个1和另一个1相撞的时候它不是最小值也没关系,最后会被更新掉),同时计算一下两个0相撞时0能取到的最大值,可以用一个set维护,因为我们需要删掉枚举的1所带的那个0,除了它所在的类型只有1个的情况

    代码

        #include <bits/stdc++.h>
        #define fi first
        #define se second
        #define pii pair<int,int>
        #define mp make_pair
        #define pb push_back
        #define enter putchar('
    ')
        #define space putchar(' ')
        //#define ivorysi
        #define MAXN 100005
        typedef long long int64;
        using namespace std;
        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 + 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 p[MAXN][2],sum,ans,t3;
        int L[MAXN],R[MAXN],tot,ty[MAXN],cnt[10];
        pii pos[MAXN * 2];
        multiset<int64> S;
        bool cmp(pii a,pii b) {
        	return p[a.fi][a.se] < p[b.fi][b.se];
        }
        void Solve() {
            read(N);
        	for(int i = 1 ; i <= N ; ++i) {
        		read(p[i][1]);read(p[i][0]);
        		ans += p[i][1] + p[i][0];
        		pos[++tot] = mp(i,0);
        		pos[++tot] = mp(i,1);
        	}
        	sort(pos + 1,pos + tot + 1,cmp);
        	for(int i = 1 ; i <= tot / 2 ; ++i) {
        		sum += p[pos[i].fi][pos[i].se];
        		if(!pos[i].se) L[pos[i].fi] = 1;
        		else R[pos[i].fi] = 1;
        		S.insert(p[pos[i].fi][pos[i].se]);
        	}
        	for(int i = 1 ; i <= N ; ++i) {
        		if(L[i] && !R[i]) {ty[i] = 1;cnt[1]++;}
        		if(!L[i] && R[i]) {ty[i] = 2;cnt[2]++;}
        		if(!L[i] && !R[i]) {ty[i] = 3;cnt[3]++;}
        		if(L[i] && R[i]) {ty[i] = 4;cnt[4]++;}
        	}
        	if(!cnt[1] || !cnt[2] || cnt[3]) {out(sum);enter;return;}
        	for(int i = tot / 2 + 1 ; i <= tot ; ++i) {
        		int u = pos[i].fi;
        		if(cnt[ty[u]] != 1) {
        			S.erase(S.find(p[u][pos[i].se ^ 1]));
        			ans = min(ans,sum + p[pos[i].fi][pos[i].se] - *(--S.end()));
        			S.insert(p[u][pos[i].se ^ 1]);
        		}
        		else ans = min(ans,sum + p[pos[i].fi][pos[i].se] - *(--S.end()));
        	}
        	out(ans);enter;
        }
        int main() {
        #ifdef ivorysi
        	freopen("f1.in","r",stdin);
        #endif
        	Solve();
        	return 0;
        }
    

    D - Chords

    这题看起来很繁琐,但是实际上逻辑很简单

    (dp[i][j])表示一个联通块标记为(i)为最小的标号,(j)为最大的标号,这样的方案有多少个

    首先要满足初始的时候(i,j)之间的点没有连到外部的点

    然后计算方案是(g(x))
    x是(i,j)之间没有匹配的点的个数,(g(x) = 1*3*5...(x - 3)(x - 1))

    然后再减掉不合法的方案

    (dp[i][j] -= dp[i][k] * g(z))z是(k + 1,j)中没有匹配过的点

    最后输出的时候还要乘上一个(g(y))y表示所有除了(i,j)之外未匹配的点

    代码

        #include <iostream>
        #include <cstring>
        #include <cstdio>
        #include <algorithm>
        #define enter putchar('
    ')
        #define space putchar(' ')
        #define fi first
        #define se second
        #define mp make_pair
        #define MAXN 200005
        //#define ivorysi
        #define pii pair<int,int>
        using namespace std;
        typedef long long int64;
        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 + c - '0';
        	c = getchar();
            }
            res *= f;
        }
         
        template<class T>
        void out(T x) {
            if(x < 0) {putchar('-');x = -x;}
            if(x >= 10) out(x / 10);
            putchar('0' + x % 10);
        }
        const int MOD = 1000000007;
        int N,K;
        int A[305],B[305];
        int cnt[605][605],dp[605][605],g[605];
        bool vis[605][605];
        bool in(int a,int l,int r) {
            return a >= l && a <= r;
        }
        int inc(int a,int b) {
            return a + b >= MOD ? a + b - MOD : a + b;
        }
        int mul(int a,int b) {
            return 1LL * a * b % MOD;
        }
        void Solve() {
            read(N);read(K);
            for(int i = 1 ; i <= K ; ++i) {
        	read(A[i]);read(B[i]);
            }
            g[0] = 1;
            for(int i = 1 ; i <= 2 * N ; ++i) {
        	if(i & 1) g[i] = 0;
        	else g[i] = mul(g[i - 2],i - 1);
            }
            for(int i = 1 ; i <= 2 * N ; ++i) {
        	for(int j = i + 1 ; j <= 2 * N ; ++j) {
        	    for(int h = 1 ; h <= K ; ++h) {
        		if(in(A[h],i,j) && in(B[h],i,j)) {
        		    ++cnt[i][j];
        		}
        		else if((!in(A[h],i,j) && in(B[h],i,j)) || (in(A[h],i,j) && !in(B[h],i,j))) {
        		    vis[i][j] = 1;
        		    break;
        		}
        	    }
        	}
            }
            for(int d = 2 ; d <= 2 * N ; d += 2) {
        	for(int i = 1 ; i <= 2 * N ; ++i) {
        	    int j = i + d - 1;
        	    if(j > 2 * N) break;
        	    if(vis[i][j]) continue;
        	    int x = j - i + 1 - 2 * cnt[i][j];
        	    dp[i][j] = g[x];
        	    for(int h = i + 1 ; h < j ; h += 2) {
        		if(!dp[i][h]) continue;
        		x = j - h - 2 * cnt[h + 1][j]; 
        		dp[i][j] = inc(dp[i][j],MOD - mul(dp[i][h],g[x]));
        	    }
        	}
            }
            int ans = 0;
            for(int i = 1 ; i <= 2 * N ; ++i) {
        	for(int j = i + 1 ; j <= 2 * N ; j += 2) {
        	    int y = 2 * N - (j - i + 1 - 2 * cnt[i][j]) - 2 * K; 
        	    ans = inc(ans,mul(dp[i][j],g[y]));
        	}
            }
            out(ans);enter;
        }
         
        int main() {
        #ifdef ivorysi
            freopen("f1.in","r",stdin);
        #endif
            Solve();
        }
    

    E - High Elements

    我们需要已知部分(X)(Y)的情况下,知道后面的数能不能使得最终情况合法

    我们设(X)高元素的个数为(C_x)(Y)高元素个数为(C_y)

    我们还需要两个高元素序列(a,b)满足(C_x + |a| = C_y + |b|)

    我们可以保证(a,b)至少有一个,其中所有的高元素都是p原来的高元素,证明这个,我们只要找到两个合法的序列,然后每次减少两个序列中高元素,直到不能减了

    这样的话我们设(a)全是P原来的高元素组成的序列

    然后我们决定一下(b)(b)确定了(a)就自动是未选的所有高元素了

    (b)中的高元素有(k)个是P中的高元素,(m)是非高元素,剩下的序列中有Q个是高元素

    那么我们满足
    (C_x + Q - k = C_y + |b|)
    (C_x + Q - k = C_y + k + m)
    (2k + m = C_x - C_y + Q)

    也就是我们设所有高元素长度为2,非高元素长度为1,求一个上升子序列,看看长度是否正好为一个常数

    我们只需要分奇偶性找一个最长的升子序列,和这个常数比较一下就行
    需要用线段树维护dp状态

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int,int>
    #define mp make_pair
    #define pb push_back
    #define MAXN 200005
    //#define ivorysi
    #define space putchar(' ')
    #define enter putchar('
    ')
    using namespace std;
    typedef long long int64;
    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 + c - '0';
    	c = getchar();
        }
        res *= f;
    }
    template<class T>
    void out(T x) {
        if(x < 0) {x = -x;}
        if(x >= 10) {
    	out(x / 10);
        }
        putchar('0' + x % 10);
    }
    int N,P[MAXN],val[MAXN],ans[MAXN],curx,cury;
    struct node {
        int maxv,L,R,lc,rc;
    }tr[MAXN * 20];
    int rt[2],Ncnt;
    void build(int &u,int L,int R,int v) {
        u = ++Ncnt;
        tr[u].L = L;tr[u].R = R;
        tr[u].maxv = v;
        if(L == R) return;
        int mid = (L + R) >> 1;
        build(tr[u].lc,L,mid,v);
        build(tr[u].rc,mid + 1,R,v);
    }
    void Change(int u,int pos,int v) {
        if(tr[u].L == tr[u].R) {tr[u].maxv = v;return;}
        int mid = (tr[u].L + tr[u].R) >> 1;
        if(pos <= mid) Change(tr[u].lc,pos,v);
        else Change(tr[u].rc,pos,v);
        tr[u].maxv = max(tr[tr[u].lc].maxv,tr[tr[u].rc].maxv);
    }
    int Query(int u,int l,int r) {
        if(tr[u].L == l && tr[u].R == r) return tr[u].maxv;
        int mid = (tr[u].L + tr[u].R) >> 1;
        if(r <= mid) return Query(tr[u].lc,l,r);
        else if(l > mid) return Query(tr[u].rc,l,r);
        else return max(Query(tr[u].lc,l,mid),Query(tr[u].rc,mid + 1,r));
    }
    void Solve() {
        read(N);
        for(int i = 1 ; i <= N ; ++i) read(P[i]);
        int cur = 0,Q = 0;
        for(int i = 1 ; i <= N ; ++i) {
    	cur = max(cur,P[i]);
    	if(cur == P[i]) {val[i] = 2;++Q;}
    	else val[i] = 1;
        }
        build(rt[0],1,N + 1,0);build(rt[1],1,N + 1,-2 * N);
        for(int i = N ; i >= 1 ; --i) {
    	int tmp[2];
    	for(int j = 0 ; j < 2 ; ++j) tmp[j] = Query(rt[j],P[i] + 1,N + 1);
    	for(int j = 0 ; j < 2 ; ++j) {
    	    if(tmp[j] + val[i] > 0) {
    		int t = (tmp[j] + val[i]) & 1;
    		Change(rt[t],P[i],tmp[j] + val[i]);
    	    }
    	}
        }
        int len[2] = {0,0},mx_num[2] = {0,0};
        for(int i = 1 ; i <= N ; ++i) {
    	ans[i] = -1;
    	Change(rt[0],P[i],0);Change(rt[1],P[i],-2 * N);
    	if(val[i] == 2) --Q;
    	for(int k = 0 ; k < 2 ; ++k) {
    	    int nxt_len[2],nxt_mx_num[2];
    	    memcpy(nxt_len,len,sizeof(len));
    	    memcpy(nxt_mx_num,mx_num,sizeof(mx_num));
    	    nxt_mx_num[k] = max(nxt_mx_num[k],P[i]);
    	    if(nxt_mx_num[k] == P[i]) ++nxt_len[k];
    	    if(i == N) {
    		if(nxt_len[0] == nxt_len[1]) {ans[i] = k;break;}
    		continue;
    	    }
    	    bool flag = 0;
    	    
    	    for(int j = 0 ; j < 2 ; ++j) {
    		int t = nxt_len[j] - nxt_len[j ^ 1] + Q;
    		if(t >= 0 && Query(rt[t & 1],nxt_mx_num[j ^ 1] + 1,N + 1) >= t) {flag = 1;break;}
    	    }
    	    if(flag) {
    		ans[i] = k;
    		memcpy(len,nxt_len,sizeof(len));
    		memcpy(mx_num,nxt_mx_num,sizeof(mx_num));
    		break;
    	    }
    	}
    	if(ans[i] < 0) {
    	    puts("-1");return;
    	}
        }
        for(int i = 1 ; i <= N ; ++i) putchar('0' + ans[i]);
        enter;
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Solve();
    }
    
    
  • 相关阅读:
    RecycleView点击事件
    RecycleView 的使用 (CardView显示每个小项)
    wine
    git
    ubuntu 装机
    tar 压缩为多个文件&解压缩
    make error: makefile:4: *** missing separator. Stop
    python中的PEP是什么?怎么理解?(转)
    博客园如何转载别人的文章(转)
    信息熵
  • 原文地址:https://www.cnblogs.com/ivorysi/p/9791840.html
Copyright © 2011-2022 走看看