0%

题目大意

题目设定
给定一个包含 kk1k261 \le k \le 26)首短歌的曲库,分别用前 kk 个大写英文字母表示。
由这 kk 首歌可以生成一个无限长的母带(master track)tt。生成方式为:不断重复这 kk 首歌,但在每一次重复整个曲库时,都会将当前序列的第一首歌移动到序列的末尾。
例如,当 k=4k = 4 时,曲库初始为 ABCD,那么母带 tt 就是无限长的字符串 ABCD BCDA CDAB DABC ABCD ...

有一个长度为 nn 的播放列表,初始时全部为空白。在此问题中,播放列表和母带均从 1 开始索引。

操作要求
需要对播放列表执行 qq 次操作,操作分为以下两种:

  1. + i a b:将播放列表中从位置 aabb(包含两端)的片段,替换为母带 tt 中从位置 ii 开始、长度为 ba+1b - a + 1 的子串。

  2. ? a b:查询播放列表中从位置 aabb(包含两端)的片段。输出 kk 个整数,其中第 jj 个整数表示该片段中第 jj 个英文字母(即第 jj 首歌)的出现次数。

输入格式
第一行包含三个空格分隔的整数 kknnqq
接下来 qq 行,每行描述一个操作,格式为 + i a b? a b

输出格式
对于每一个 ? a b 操作,输出一行包含 kk 个空格分隔的整数,表示查询的结果。

数据范围
1k261 \le k \le 26
1n1091 \le n \le 10^9
1q1051 \le q \le 10^5
每次操作中:1i1091 \le i \le 10^91abn1 \le a \le b \le n

样例输入

1
2
3
4
5
4 10 4
+ 7 2 6
+ 2 8 10
+ 9 1 4
? 4 9

样例输出

1
1 2 1 1

样例解释
在此样例中,k=4k = 4n=10n = 10。母带 ttABCDBCDACDABDABC...
播放列表初始为空,我们用星号代表空白部分:**********

  1. 执行 + 7 2 6
    我们需要一个长度为 62+1=56 - 2 + 1 = 5 的子串。
    母带 tt 中从位置 7 开始、长度为 5 的子串是 DACDA
    将播放列表中第 2 到第 6 首歌替换为该子串,此时播放列表变为:DACDA****

  2. 执行 + 2 8 10
    播放列表第 8 到 10 的位置被替换后变为:DACDA*BCD

  3. 执行 + 9 1 4
    覆盖掉前 4 个位置的歌曲,播放列表最终变为:CDABDA*BCD

  4. 执行 ? 4 9
    查看当前播放列表中第 4 到第 9 首歌,对应片段为 BDA*BC
    需要输出 A、B、C、D 四个字母在此片段内分别出现的次数。因此,输出 1 2 1 1

思路讲解

其实还是很明显的动态开点线段树。我说白了是个动态开点线段树的云玩家,我都看出来是动态开点线段树了。

P13825 【模板】线段树 1.5(指针式动态开点线段树)

既然是这个动态开点线段树,我们想一想,我们的 apply 函数如何书写吧。

其实最重要的是,在知道母带上 l,r 的情况下,求出母带上的 cnt 数组。

get_range_cnt,可以变为 get_pref_cnt®-get_pref_cnt(l - 1),是一个非常经典的套路。

1
2
3
4
5
6
7
8
array<int, 26> get_range_cnt(ll l, ll r) {
auto R = get_pref_cnt(r);
auto L = get_pref_cnt(l - 1);
for (int i = 0; i < k; ++i) {
R[i] -= L[i];
}
return R;
}

AC代码

AC
https://codeforces.com/gym/106262/submission/365836934

心路历程(WA,TLE,MLE……)

image

image

image

题目大意

题目总结

Bob 有 nn 瓶酒精饮料,标号为 11nn。已知第 ii 瓶饮料包含 viv_i 单位的液体体积,其中有 aia_i 单位是纯酒精(0aivi0 \le a_i \le v_i)。因此,第 ii 瓶饮料的酒精浓度为 ai/via_i / v_i。每瓶饮料是完全均匀的,从中取出任意体积的液体,其酒精浓度均保持不变。

Bob 可以从这些瓶子中选择任意组合,并从每瓶中取出任意体积(不必须为整数)的液体进行混合。

现在提出一个挑战:
V=i=1nviV = \sum_{i=1}^n v_i 为所有瓶子中液体的总体积。
[0,V][0, V] 区间内均匀随机生成一个实数 ss(目标总体积)
[0,1][0, 1] 区间内均匀随机生成一个实数 ff(目标酒精浓度)

请计算:Bob 能够成功调配出总体积恰好为 ss、且酒精浓度恰好为 ff 的饮品的概率是多少?(输出结果与标准答案的绝对或相对误差需不超过 10810^{-8})。

输入格式
第一行包含一个整数 nn2n2×1052 \le n \le 2 \times 10^5)。
第二行包含 nn 个整数,依次为 v1,v2,,vnv_1, v_2, \dots, v_n1vi1091 \le v_i \le 10^9)。
第三行包含 nn 个整数,依次为 a1,a2,,ana_1, a_2, \dots, a_n0aivi0 \le a_i \le v_i)。

样例输入

1
2
3
3
350 750 330
140 131 16

样例输出

1
0.19356182654786474591

样例解释
在这个样例中,所有液体的总体积 V=350+750+330=1430V = 350 + 750 + 330 = 1430

我们可以考虑两种具体的情况:
第一种情况:假设生成的 s=500s = 500f=313f = \frac{3}{13}。此时 Bob 是可以成功调配的。例如,他可以从第 11 瓶中取出 97750377\frac{97750}{377} 单位的液体,从第 33 瓶中取出 90750377\frac{90750}{377} 单位的液体。
调配出的总体积为 97750377+90750377=188500377=500\frac{97750}{377} + \frac{90750}{377} = \frac{188500}{377} = 500
调配出的酒精浓度为:

97750377×140350+90750377×16330500=313 \frac{\frac{97750}{377} \times \frac{140}{350} + \frac{90750}{377} \times \frac{16}{330}}{500} = \frac{3}{13}

第二种情况:假设生成的 s=814s = 814f=0.1234567f = 0.1234567。此时 Bob 是无法完成调配的,因为利用他现有的饮料集合无法混合出该体积和浓度的饮品。

综合考虑所有可能在给定范围内均匀生成的 ssff 的数值对 (s,f)(s, f),Bob 能够成功调配的概率约为 0.193561826547864745910.19356182654786474591

思路讲解

概率转化为可行域面积占总面积的比重,这一点对两参数随意取的概率问题特别有用。

image

具体而言,我们的这个分段函数应该长这样:

image

其不定积分是长这样的,带进去值,算一下定积分即可。

image

AC代码

AC
https://qoj.ac/submission/2106344
AC
https://codeforces.com/gym/106262/submission/365722146

心路历程(WA,TLE,MLE……)

注意,分段函数不是线性的,而是一个分段反比例函数。

image

不要一会用 x,一会用 v,但是代表同一个意思。

image

题目大意

题目名称: Stone Steps

题目描述:
给定一个仅包含非零十进制数字的字符串 ss(长度 1s5×1051 \le |s| \le 5 \times 10^5)。

对于任意不包含数字 0 的正整数 nn,定义 H(n)H(n) 为将 nn 的所有数位按非降序(从小到大)重新排序后得到的新整数。例如:H(1971)=1179H(1971) = 1179H(3)=3H(3) = 3

你的任务是计算字符串 ss 的所有非空连续子串所代表的十进制整数的 HH 函数值之和。即对于所有满足 1ijs1 \le i \le j \le |s| 的子串 s[i...j]s[i...j],求出 H(s[i...j])H(s[i...j]) 并求和。最终的结果需要对 1000696967 取模后输出。

输入格式:
单行输入一个字符串 ss

输出格式:
输出一个整数,表示所有非空连续子串的 HH 函数值之和对 1000696967 取模的结果。

样例 1:

1
2
3
4
5
输入:
3141

输出:
1432

样例 1 解释:
ss3141 时,共有 10 个非空连续子串,计算过程如下:

  • s[1...1]s[1...1]3H(3)=3H(3) = 3

  • s[2...2]s[2...2]1H(1)=1H(1) = 1

  • s[3...3]s[3...3]4H(4)=4H(4) = 4

  • s[4...4]s[4...4]1H(1)=1H(1) = 1

  • s[1...2]s[1...2]31H(31)=13H(31) = 13

  • s[2...3]s[2...3]14H(14)=14H(14) = 14

  • s[3...4]s[3...4]41H(41)=14H(41) = 14

  • s[1...3]s[1...3]314H(314)=134H(314) = 134

  • s[2...4]s[2...4]141H(141)=114H(141) = 114

  • s[1...4]s[1...4]3141H(3141)=1134H(3141) = 1134

将其相加得:3+1+4+1+13+14+14+134+114+1134=14323 + 1 + 4 + 1 + 13 + 14 + 14 + 134 + 114 + 1134 = 1432

样例 2:

1
2
3
4
5
输入:
1

输出:
1

样例 3:

1
2
3
4
5
输入:
11234567891234567891

输出:
43138332

思路讲解

还是要使用拆分算贡献的思想。

我们还需要利用一个东西,就是数位,其实只有 9 个,所以我们不用想着一次遍历去解决,可以遍历 9 次。

不过,我认为最有用的,还是把这个所有的东西,贡献,全部写下来。然后看看有什么规律。全部都写下来以后,我们发现这个规律非常的简单。

image

然后就跟着上面的这个公式求就完了。

以样例一具体而言就是:

image

推这种式子就是要细心。

AC代码

AC

https://codeforces.com/gym/106262/submission/365694725

心路历程(WA,TLE,MLE……)

在处理 lans,也就是背后的时候,忘记处理了不含 i7 的情况,即什么都不含,只含 i5 的背后情况。

image

题目大意

题目描述
Alice 和 Bob 在一个无向简单图上玩改进版的井字棋游戏。这个图有 nn 个顶点(代表方格)和 mm 条边。
游戏规则如下:

  1. 初始时,所有顶点都是空的。

  2. 两人轮流行动,Alice 先手。

  3. 在 Alice 的回合,她选择一个空的顶点并画上 X

  4. 在 Bob 的回合,他选择一个空的顶点并画上 O

  5. 游戏总共进行 5 个回合,也就是说 Alice 总是行动 3 次,Bob 总是行动 2 次。

  6. 如果 Alice 能够将她画了 X 的 3 个顶点连成一条长度为 3 的路径(注意:这 3 个顶点在路径中的顺序不一定与她落子的顺序相同),那么 Alice 获胜。如果 Bob 能阻止这一切发生,则 Bob 获胜。

假设双方在第一步之后都采取完美策略。请计算:Alice 有多少种可能的第一步选择,使得无论 Bob 随后如何应对,她都必胜?

输入格式
第一行包含两个由空格分隔的整数 nnmm5n2×105,0mmin(2×105,n(n1)/2)5 \le n \le 2 \times 10^5, 0 \le m \le \min(2 \times 10^5, n(n - 1)/2)),分别表示图的顶点数和边数。
接下来 mm 行,每行包含两个由空格分隔的整数 uuvv1u,vn1 \le u, v \le n),表示顶点 uuvv 之间有一条边。
保证图中没有自环和重边。

输出格式
输出一个整数,表示能让 Alice 必胜的初始落子位置的数量。

样例输入

1
2
3
4
5
6
7
8
9
10
8 9
1 2
1 4
1 5
2 3
2 7
3 4
3 5
3 6
4 6

样例输出

1
5

样例解释

image

image

对于该图,如果 Alice 第一步下在顶点 1、2、3、4 或 5,那么在双方完美发挥的情况下,她必定能获胜。
以第一步下在顶点 1 为例,其中一种可能的游戏进程是:

  • Alice 在 1 画 X

  • Bob 在 4 画 O

  • Alice 在 2 画 X

  • Bob 在 3 画 O

  • Alice 在 7 画 X
    此时 Alice 在 1、2、7 画了 X,它们构成了一条长度为 3 的路径(1-2-7),因此 Alice 获胜。
    如果她第一步下在 6、7 或 8,那么在 Bob 完美应对的情况下,她注定会输。
    必胜的起始点有 5 个,因此输出 5。

思路讲解

遇到图上问题,没有特殊结构以及这个数据比较大,那么基本上就可以排除 dp 的可能性了

那说白了,我们还有其他工具吗?

我们回归原始,对度数进行分类讨论。

首先,度数 ≥ 4,一定是必胜起始点。

image

度数为 3 的时候,不难得出:⚠️ 注意:需要两个,否则你刚走一步,他就把你唯一一条生路给堵死了,你不就死了吗。

image

度数为 2 的情况:

image

度数为 1 自然是不可能的。

然后好像就做完了?绷不住了

AC代码

AC
https://codeforces.com/gym/106262/submission/365635347

心路历程(WA,TLE,MLE……)

题目大意

题目描述
Gagamboy 需要购买 rr 种不同的化学物质,每种需要 1kg。电商平台上共有 cc 个卖家。
给定一个 r×cr \times c 的价格矩阵 AA,其中 ai,ja_{i,j} 表示从卖家 jj 处购买 1kg 化学物质 ii 的价格。
此外,对于每个卖家 jj,只要从该卖家处购买了任何数量的化学物质(哪怕只有一种),都需要额外支付一笔固定的配送费 djd_j
请计算购买到所有 rr 种化学物质(每种至少 1kg)所需的最小总花费。本题包含多组独立测试数据。

输入格式
第一行包含一个整数 TT1T101 \le T \le 10),表示测试数据的组数。
对于每组测试数据:
第一行包含两个由空格分隔的整数 rrcc1r,c1 \le r, c,且 r×c250r \times c \le 250)。
接下来 rr 行,每行包含 cc 个由空格分隔的整数,第 ii 行的第 jj 个数为 ai,ja_{i,j}1ai,j10151 \le a_{i,j} \le 10^{15})。
最后一行包含 cc 个由空格分隔的整数 d1,d2,,dcd_1, d_2, \dots, d_c1dj10151 \le d_j \le 10^{15}),表示每个卖家的配送费。

输出格式
对于每组测试数据,输出一行一个整数,表示完成购买所需的最小总花费。

样例输入

1
2
3
4
5
6
7
8
9
10
11
12
2
3 5
1 3 5 7 9
5 7 9 1 3
9 1 3 5 7
4 3 2 3 4
4 3
1 2 4
2 3 1
4 1 2
3 2 1
2 4 4

样例输出

1
2
11
11

样例解释
对于第一组样例:
一种最优的购买方案如下:

  • 向卖家 2 购买化学物质 1 和 3。它们的价格分别为 a1,2=3a_{1,2} = 3a3,2=1a_{3,2} = 1。支付这笔订单所需的配送费为 d2=3d_2 = 3

  • 向卖家 4 购买化学物质 2。它的价格为 a2,4=1a_{2,4} = 1。支付这笔订单所需的配送费为 d4=3d_4 = 3
    总花费为:((3+1)+3)+(1+3)=11((3 + 1) + 3) + (1 + 3) = 11

对于第二组样例:
最优方案能达到的最小花费同样为 11。

思路讲解

这道题目的做法,首先,需要想到:绷不住了,这道题目,观察到 chem * sell <= 250,那么,chem,sell 理论上来说,应该不会同时超过 16,因为 16*16=256,这样子,chem 小,就对 chem 进行状态压缩sell 小,就对 sell 进行状态压缩

确实是感觉到,如果不进行状态压缩,那么这道题目非常难做

如果进行状态压缩的话,状态压缩 seller 非常好做。枚举的是给哪些 seller 付了这个运费。

给哪些 seller 付了这个运费,就只能从这些 seller 这里购买化学品。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
ll ans=INF;
// 枚举的是给哪些 seller 付了这个运费
for (int s=1;s<(1<<M_j_sell);++s) {
vector<ll> mn_price(N_i_chem+2,INF);
ll offset_j=1;
ll price=0;
// 给哪些 seller 付了这个运费,就只能从这些 seller 这里购买化学品
for (int j=0;j<M_j_sell;++j) {
if (s>>j&1) {
price+=D_j_sell[j+offset_j];
for (int i=1;i<=N_i_chem;++i) {
mn_price[i]=min(mn_price[i],A[i][offset_j+j]);
}
}
}
for (int i=1;i<=N_i_chem;++i) {
price+=mn_price[i];
}
ans=min(ans,price);
// dp[s]=price;
}
cout<<ans<<"\n";

我们来看,状态压缩 chem,我们怎么做?这个会难一点。

我们不难观察到,一个子集 S 的最优解,一定是这样的:把一部分子集交给一个买家,把另一部分子集交给一个买家,把又一部分子集交给又一买家……。

在状态压缩 化学品的时候,我们需要学习一种写法,即枚举 mask 的子集。

1
2
3
4
5
6
for (int S = 0; S < (1 << r); S++) {
for (int T = S; T > 0; T = (T - 1) & S) {
// T 是 S 的非空子集
dp[S] = min(dp[S], dp[S ^ T] + best[T]);
}
}

枚举 mask 的所有子集,是 O(3n)O(3^n)

如果说枚举 seller,允许你去这个枚举子集,是不是会简单一点?

预处理:对每个非空子集 TT,预先算好从所有卖家中买 TT 的最小花费:best(T)的意思就是在包括这个运费的情况下,该 chem 子集 T,从哪一个买家那里采购,所需花费最低

best(T)=minj=1c(dj+iTai,j)\text{best}(T) = \min_{j=1}^{c} \left(d_j + \sum_{i \in T} a_{i,j}\right)

具体而言就是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ll offset_i=1;
vector<ll> best((1<<N_i_chem)+2);
for (int s=1;s<(1<<N_i_chem);++s) {
ll lans=INF;
for (int j=1;j<=M_j_sell;++j) {
ll price=D_j_sell[j];
for (int i=0;i<N_i_chem;++i) {
if (s>>i&1) {
price+=A[offset_i+i][j];
}
}
lans=min(lans,price);
}
best[s]=lans;
}

转移方程如下,容易写出:

dp[S]=minTS(dp[ST]+best(T))dp[S] = \min_{\emptyset \neq T \subseteq S} \left(dp[S \setminus T] + \text{best}(T)\right)

你可能会有疑问,这个运费会不会重复算?答案是是的,但是我们肯定不会采用运费重复算的组合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
vector<ll> dp((1<<N_i_chem)+2);
// for (int j=1;j<=M_j_sell;++j) {
// dp[0][j]=0;
// }
// for (int s=1;s<(1<<N_i_chem);++s) {}
ll offset_i=1;
vector<ll> best((1<<N_i_chem)+2);
for (int s=1;s<(1<<N_i_chem);++s) {
ll lans=INF;
for (int j=1;j<=M_j_sell;++j) {
ll price=D_j_sell[j];
for (int i=0;i<N_i_chem;++i) {
if (s>>i&1) {
price+=A[offset_i+i][j];
}
}
lans=min(lans,price);
}
best[s]=lans;
}
for (int s=1;s<(1<<N_i_chem);++s) {
ll lans=INF;
for (int t=s;t>0;t=(t-1)&s) {
lans=min(lans,dp[s^t]+best[t]);
}
dp[s]=lans;
}
cout<<dp[(1<<N_i_chem)-1]<<"\n";

AC代码

AC
https://codeforces.com/gym/106262/submission/365538444

心路历程(WA,TLE,MLE……)