【Atcoder】AGC020 C-F简要题解

版权声明:欢迎转载(请附带原链接)ヾ(๑╹◡╹)ノ https://blog.csdn.net/corsica6/article/details/88732034

C.Median Sum

题解


D.Min Max Repetition

最短相同子串长度 x = max ( A , B ) min ( A , B ) + 1 x=\lceil\dfrac{\max(A,B)}{\min(A,B)+1}\rceil

字典序最小的串必然前半部分是一段 A × x , B , A × x , . . . A\times x,B,A\times x,...

存在位置 p o s pos 使得前半部分维持到 p o s pos 时,剩余的 A , B A',B' 满足 B > A x B'>Ax

( p o s + 1 ) ( A + B ) (pos+1)-(A+B) 的后半部分就是一段 B . . B , A , B × x , A , B × x B..B,A,B\times x,A,B\times x

二分寻找 p o s pos 即可。


E.Encoding Subsets

区间DP:

f [ S ] , g [ S ] f[S],g[S] 分别表示01串 S S 子集的方案数和不可分割(长度为1或左右均为括号)的方案数。

边界 g [ S ] = S 0    ( S = 1 ) , f [ ] = 1 g[|S|]=S-'0' \ \ (|S|=1),f[空串]=1 ,转移:

f [ S ] = T S T g [ T ] × f [ S T ] f[S]=\sum\limits_{T是S的前缀且T不为空串}g[T]\times f[S-T]
g [ S ] = T S T S f [ T ] g[S]=\sum\limits_{T是S的循环节且T \neq S}f[T]

g g 转移的时候把强制有循环节按位与即可。
答案是 f [ ] f[原串]

玄学记搜就过了

code from xyz32768

#include <map>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Step(i, a, b, x) for (i = a; i <= b; i += x)
using namespace std;
inline int read() {
    int res = 0; bool bo = 0; char c;
    while (((c = getchar()) < '0' || c > '9') && c != '-');
    if (c == '-') bo = 1; else res = c - 48;
    while ((c = getchar()) >= '0' && c <= '9')
        res = (res << 3) + (res << 1) + (c - 48);
    return bo ? ~res + 1 : res;
}
const int PYZ = 998244353;
map<string, int> f, g;
int F(string); int G(string);
int G(string s) {
    if (g[s]) return g[s]; int i, n = s.size(); if (n == 1) return g[s] = s[0] - '0' + 1;
    int j, k, res = 0; For (i, 1, n - 1) if (n % i == 0) {
        string t = ""; For (j, 1, i) {
            int r = 1; Step (k, j - 1, n - 1, i) r &= s[k] - '0';
            t += (char) (r + '0');
        }
        res = (res + F(t)) % PYZ;
    }
    return g[s] = res;
}
int F(string s) {
    if (f[s]) return f[s]; int i, n = s.size(); if (!n) return f[s] = 1;
    int res = 0; For (i, 1, n)
        res = (res + 1ll * G(s.substr(0, i)) * F(s.substr(i, n)) % PYZ) % PYZ;
    return f[s] = res;
}
int main() {
    string s; cin >> s; cout << F(s) << endl;
    return 0;
}

*F.Arcs on a Circle

Tourist的神题,做是不可能做出来的,题解wxh010910

L L 最大的弧的左端点为原点。其它弧的左端点都可以用一个实数表示。

发现位置整数部分是 [ 0 , C ) [0,C) 的一个随机值,小数部分是 [ 0 , 1 ) [0,1) 均匀随机的一个实数。我们不关心小数部分的具体值,只关心 n n 条弧的小数部分相对大小。

于是 ( n 1 ) ! (n-1)! 枚举小数部分相对大小的排列(等概率出现) ,在 N × C N\times C 个位置上DP:
d p [ i ] [ j ] dp[i][j] 表示已经放上的圆弧状态为 j j ,覆盖最远点为 i i 的方案数。

code from Factorio

#include <bits/stdc++.h>
using namespace std;
double z, f[320][33], t;
int n, c, a[9];
int main() {
	cin >> n >> c;
	for (int i = 0; i < n; i++) {
		cin >> a[i];
	}
	sort(a, a + n);
	do {
		memset(f, 0, sizeof f);
		f[n * a[n - 1]][0] = 1;
		for (int i = 0; i < n * c; i++) {
			for (int j = i; j <= n * c; j++) {
				for (int k = 0; k < (1 << (n - 1)); k++) {
					if (i % n && (k >> (i % n - 1) & 1) == 0) {
						f[min(max(j, i + n * a[i % n - 1]), n * c)][k | (1 << (i % n - 1))] += f[j][k];
					}
				}
			}
		}
		z += f[n * c][(1 << (n - 1)) - 1];
		t++;
	} while (next_permutation(a, a + n - 1));
	printf("%.15f\n", z / t / pow(c, n - 1));
	return 0;
}

猜你喜欢

转载自blog.csdn.net/corsica6/article/details/88732034