【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('\n')
#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('\n')
#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('\n')
#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('\n')
#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('\n')
#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('\n')
#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\n",ans);
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
    return 0;
}
posted @ 2018-12-22 19:07  sigongzi  阅读(472)  评论(0编辑  收藏  举报