zoukankan      html  css  js  c++  java
  • 【AtCoder】AGC020

    A - Move and Win

    题解

    看两个人相遇的时候谁先手即可,相遇之后第一个移动的人必输

    代码

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int,int>
    #define pdi pair<db,int>
    #define mp make_pair
    #define pb push_back
    #define enter putchar('
    ')
    #define space putchar(' ')
    #define eps 1e-8
    #define mo 974711
    #define MAXN 2005
    //#define ivorysi
    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 + 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,A,B;
    
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        read(N);read(A);read(B);
        int t = abs(B - A - 1);
        if(t & 1) puts("Alice");
        else puts("Borys");
        return 0;
    }
    

    B - Ice Rink Game

    题解

    二分直接判断即可

    代码

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int,int>
    #define pdi pair<db,int>
    #define mp make_pair
    #define pb push_back
    #define enter putchar('
    ')
    #define space putchar(' ')
    #define eps 1e-8
    #define mo 974711
    #define MAXN 100005
    //#define ivorysi
    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 + 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 K;
    int64 A[MAXN];
    int64 check(int64 x) {
        for(int i = 1 ; i <= K ; ++i) {
    	x -= x % A[i];
        }
        return x;
    } 
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        read(K);
        for(int i = 1 ; i <= K ; ++i) read(A[i]);
        int64 L = 2,R = 1e18;
        while(L < R) {
    	int64 mid = (L + R) >> 1;
    	if(check(mid) >= 2) R = mid;
    	else L = mid + 1;
        }
        if(check(R) != 2) {puts("-1");return 0;}
        out(R);space;
        R = 1e18;
        while(L < R) {
    	int64 mid = (L + R + 1) >> 1;
    	if(check(mid) <= 2) L = mid;
    	else R = mid - 1;
        }
        out(R);enter;
    }
    

    C - Median Sum

    题解

    我们把子序列两两配对

    也就是一个子序列选了其中的k个,另一个子序列选了其中的n - k个,进行配对

    显然我们一个对内的子序列,肯定一个小于等于(frac{sum[n]}{2})

    另一个大于等于(frac{sum[n]}{2})

    由于全集没有配对,所以肯定中位数就是大于等于(frac{sum[n]}{2})的第一个

    代码

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int,int>
    #define pdi pair<db,int>
    #define mp make_pair
    #define pb push_back
    #define enter putchar('
    ')
    #define space putchar(' ')
    #define eps 1e-8
    #define mo 974711
    #define MAXN 200005
    //#define ivorysi
    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 + 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,a[MAXN],s,cur;
    bitset<4000005> dp[2];
    void Solve() {
        read(N);
        for(int i = 1 ; i <= N ; ++i) {read(a[i]);s += a[i];}
        dp[cur].reset();
        dp[cur][0] = 1;
        for(int i = 1 ; i <= N ; ++i) {
    	dp[cur ^ 1] = (dp[cur] << a[i]) | dp[cur];
    	cur ^= 1;
        }
        for(int i = (s - 1) / 2 + 1; i <= s ; ++i) {
    	if(dp[cur][i]) {
    	    out(i);enter;return;
    	}
        }
    }
    
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Solve();
    }
    

    D - Min Max Repetition

    题解

    过于恶心的分类讨论题
    首先我们用二分求出最小的k满足题意
    求法可以是默认把A尽可能按k分块然后往能放的空隙里放B,之后默认把B尽可能按k分块然后能放的空隙里放A

    之后呢,我们特判掉A和B分的段数不相等的情况
    也就是A是1 1 1 1,B尽可能按k分块
    B是1 1 1 1,A尽可能按k分块

    之后A和B的段数就相等了
    前面肯定是A有k个B有1个A有k个B有1个
    后面肯定是A有1个B有k个A有1个B有k个
    我们二分一个两者的段数

    要求A第一个不为k的地方不可以在B第一个不为k之前两个
    且长度最大
    可以二分

    然后我们把A的每段长度求出来,相同长度的记录一个重复次数
    B同理
    之后我们拿两个指针每段合并
    合并的时候同时求一下这段如果要输出某一部分是哪里

    代码

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int,int>
    #define pdi pair<db,int>
    #define pll pair<int64,int64>
    #define mp make_pair
    #define pb push_back
    #define enter putchar('
    ')
    #define space putchar(' ')
    #define eps 1e-8
    #define mo 974711
    #define MAXN 200005
    //#define ivorysi
    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 + 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 A,B,C,D,ML;
    vector<pll > vA,vB;
    bool check(int64 a,int64 b,int64 k) {
        int64 t = (a - 1) / k;
        if(b < t) return false;
        t += 2;
        if(b > t * k) return false;
        return true;
    }
    void Process(int64 l,int64 r) {
        int p = 0,q = 0;
        int64 len = 1;
        int64 c = 0;
        while(len <= ML) {
    	int64 t = min(vA[p].se,vB[q].se);
    	vA[p].se -= t;vB[q].se -= t;
    	if(len >= l) {
    	    int64 k = t;
    	    while(k--) {
    		for(int64 i = 1 ; i <= vA[p].fi ; ++i) {
    		    putchar('A');++c;
    		    if(c == r - l + 1) return;
    		}
    		for(int64 i = 1 ; i <= vB[q].fi ; ++i) {
    		    putchar('B');++c;
    		    if(c == r - l + 1) return;
    		}
    	    }
    	}
    	else if(len + t * (vA[p].fi + vB[q].fi) - 1 >= l){
    	    int64 k = (l - len) % (vA[p].fi + vB[q].fi) + 1;
    	    int64 h = t - (l - len) / (vA[p].fi + vB[q].fi);
    	    --h;
    	    if(k <= vA[p].fi) {
    		for(int64 i = k ; i <= vA[p].fi ; ++i) {
    		    putchar('A');++c;
    		    if(c == r - l + 1) return;
    		}
    		for(int64 i = 1 ; i <= vB[q].fi ; ++i) {
    		    putchar('B');++c;
    		    if(c == r - l + 1) return;
    		}
    	    }
    	    else {
    		k -= vA[p].fi;
    		for(int64 i = k ; i <= vB[q].fi ; ++i) {
    		    putchar('B');++c;
    		    if(c == r - l + 1) return;
    		}
    	    }
    	    while(h--) {
    		for(int64 i = 1 ; i <= vA[p].fi ; ++i) {
    		    putchar('A');++c;
    		    if(c == r - l + 1) return;
    		}
    		for(int64 i = 1 ; i <= vB[q].fi ; ++i) {
    		    putchar('B');++c;
    		    if(c == r - l + 1) return;
    		}
    	    }
    	}
    	len += t * (vA[p].fi + vB[q].fi);
    	if(vA[p].se == 0) ++p;
    	if(vB[q].se == 0) ++q;
        }
    }
    void Solve() {
        read(A);read(B);read(C);read(D);
        int64 L = 1,R = max(A,B);
        ML = (A + B);
        while(L < R) {
        	int64 mid = (L + R) >> 1;
        	if(check(A,B,mid) || check(B,A,mid)) R = mid;
        	else L = mid + 1;
        }
        vA.clear();vB.clear();
        if(A == ((B - 1) / L)) {
        	int64 t = B / L;
        	int64 rem = B - L * t;
        	vA.pb(mp(0,1));
        	vA.pb(mp(1,A));
        	if(rem) vB.pb(mp(rem,1));
        	vB.pb(mp(L,t));
        }
        else if(B == (A - 1) / L){
            int64 t = A / L;
            int64 rem = A - t * L;
            vA.pb(mp(L,t));
            if(rem) vA.pb(mp(rem,1));
            vB.pb(mp(1,B));vB.pb(mp(0,1));
        }
        else {
            int64 l = max((A - 1) / L + 1,(B - 1) / L + 1),r = min(A,B);
            while(l < r) {
                int64 m = (l + r + 1) >> 1;
                int64 ta = (A - m) / (L - 1);
                int64 tb = (B - m) / (L - 1);
                ta = ta * 2 + 1;
                tb = 2 * m - (tb * 2);
                if(ta + 1 < tb) r = m - 1;
                else l = m;
            }
            if(A > l) {
                int64 ka = (A - l - 1) / (L - 1);
                int64 rem = A - l - ka * (L - 1);
                vA.pb(mp(L,ka));vA.pb(mp(1 + rem,1));vA.pb(mp(1,l - ka - 1));
            }
            else vA.pb(mp(1,l));
            if(B > l) {
                int64 kb = (B - l - 1) / (L - 1);
                int64 rem = B - l - kb * (L - 1);
                vB.pb(mp(1,l - kb - 1));vB.pb(mp(1 + rem,1));vB.pb(mp(L,kb));
            }
            else vB.pb(mp(1,l));
        }
        Process(C,D);
        enter;
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        int Q;
        read(Q);
        while(Q--) {
        	Solve();
        }
    }
    

    E - Encoding Subsets

    题解

    这题很迷,复杂度很迷
    记录(f(S))表示(S)字符串的答案

    然后要么第一个字符不要(f(S) += (s[0] + 1)f(2...|S|))
    要么就是我枚举一个长度,枚举一个压缩次数
    每段都取一个按位且的值,然后计算这个字符串压缩方案数,之后再加上后面的字符串压缩方法

    写起来容易一点可以写成记搜,然后用map记录每个string的答案

    跑了不到2s,复杂度超级迷

    代码

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int,int>
    #define pdi pair<db,int>
    #define pll pair<int64,int64>
    #define mp make_pair
    #define pb push_back
    #define enter putchar('
    ')
    #define space putchar(' ')
    #define eps 1e-8
    #define mo 974711
    #define MAXN 200005
    //#define ivorysi
    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 + 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 = 998244353;
    
    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);
    }
    map<string,int> mm;
    string operator & (const string &a,const string &b) {
        int l = a.length();
        string c(l,'0');
        for(int i = 0 ; i < l ; ++i) {
            if(a[i] == '1' && b[i] == '1') c[i] = '1';
        }
        return c;
    }
    int dfs(string s) {
        if(s.empty()) return 1;
        if(s.length() == 1) return s[0] == '0' ? 1 : 2;
        if(mm.count(s)) return mm[s];
        int res = 0;
        res = mul(s[0] == '1' ? 2 : 1,dfs(s.substr(1)));
        int l = s.length();
        for(int d = 1 ; d <= l ; ++d) {
            string t = s.substr(0,d);
            for(int k = d ; k <= l ; k += d) {
                if(k + d - 1 >= l) break;
                t = t & s.substr(k,d);
                update(res,mul(dfs(t),dfs(s.substr(k + d))));
            }
        }
        mm[s] = res;
        return res;
    }
    void Solve() {
        string s;
        cin >> s;
        out(dfs(s));enter;
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Solve();
        return 0;
    }
    

    F - Arcs on a Circle

    题解

    把最长的一段挑出来,一个端点作为0

    然后把剩下(N - 1)放置的点的位置分成整数部分和小数部分

    我们枚举一个排列,是N - 1个点小数的排列顺序,可以认为排列互不相同

    然后可以抽象出(C * N)个点,第(i)行第(j)列表示整数部分是(i)小数部分排行为(j)

    记录一个dp[a][b][S]表示当前在(a)点,最远能到b点,选了点状态为S

    答案就是dp[C * N][C * N][2^{N - 1} - 1]

    代码

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int,int>
    #define pdi pair<db,int>
    #define pll pair<int64,int64>
    #define mp make_pair
    #define pb push_back
    #define enter putchar('
    ')
    #define space putchar(' ')
    #define eps 1e-8
    #define mo 974711
    #define MAXN 200005
    //#define ivorysi
    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 + 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 a[15],L[15],N,C;
    bool vis[15];
    int64 f[2][305][(1 << 5) + 5];
    db ans,pw;
    void Process() {
        memset(f,0,sizeof(f));
        int cur = 0;
        f[cur][min(C * N,L[N] * N)][0] = 1;
        for(int i = 1 ; i < C * N ; ++i) {
            if(i % N == 0) continue;
            memset(f[cur ^ 1],0,sizeof(f[cur ^ 1]));
            int t = i % N - 1;
            for(int j = i ; j <= C * N ; ++j) {
                for(int k = 0 ; k < (1 << N - 1) ; ++k) {
                    if(!f[cur][j][k]) continue;
                    f[cur ^ 1][j][k] += f[cur][j][k];
                    if(k & (1 << t)) continue;
                    f[cur ^ 1][min(C * N,max(j,i + L[a[t + 1]] * N))][k ^ (1 << t)] += f[cur][j][k];
                }
            }
            cur ^= 1;
        }
        ans += f[cur][C * N][(1 << N - 1) - 1];
    }
    void dfs(int dep) {
        if(dep >= N) {
            Process();return;
        }
        for(int i = 1 ; i < N ; ++i) {
            if(!vis[i]) {
                a[dep] = i;
                vis[i] = 1;
                dfs(dep + 1);
                vis[i] = 0;
            }
        }
    }
    void Solve() {
        read(N);read(C);
        for(int i = 1 ; i <= N ; ++i) read(L[i]);
        sort(L + 1,L + N + 1);
        pw = 1;
        for(int i = 1 ; i < N ; ++i) pw = pw * C;
        dfs(1);
        ans *= 1.0 / pw;
        pw = 1.0;
        for(int i = 2 ; i < N ; ++i) pw = pw * i;
        ans *= 1.0 / pw;
        printf("%.11lf
    ",ans);
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Solve();
        return 0;
    }
    
  • 相关阅读:
    【梦断代码】与我们队的相似之处
    梦断代码 之 你失败过吗
    梦断代码 之 程序人生
    C#中父类转换为子类
    C#中Dictionary泛型集合7种常见的用法
    Linux 常见命令 目录处理指令
    使用XSLT+XML生成网页
    我心目中的Asp.net核心对象
    配色速成
    VS.NET中JavaScript隐藏特性
  • 原文地址:https://www.cnblogs.com/ivorysi/p/10158779.html
Copyright © 2011-2022 走看看