【Atcoder】AGC020 C-F简要题解

96 篇文章 0 订阅
32 篇文章 0 订阅

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 x=min(A,B)+1max(A,B)

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

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

( p o s + 1 ) − ( A + B ) (pos+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 B..B,A,B×x,A,B×x

二分寻找 p o s pos pos即可。


E.Encoding Subsets

区间DP:

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

边界 g [ ∣ S ∣ ] = S − ′ 0 ′    ( ∣ S ∣ = 1 ) , f [ 空 串 ] = 1 g[|S|]=S-'0' \ \ (|S|=1),f[空串]=1 g[S]=S0  (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] f[S]=TSTg[T]×f[ST]
g [ S ] = ∑ T 是 S 的 循 环 节 且 T ≠ S f [ T ] g[S]=\sum\limits_{T是S的循环节且T \neq S}f[T] g[S]=TST̸=Sf[T]

g g g转移的时候把强制有循环节按位与即可。
答案是 f [ 原 串 ] 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 L最大的弧的左端点为原点。其它弧的左端点都可以用一个实数表示。

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值