Coins Exhibition 题解

CF930E。

很水的 2900,连我都想出来了。


第一步,离散化,把所有区间离散化了,因为我们只关心每个硬币对每个区间的包含关系,并不在乎它具体是哪个。

先打暴力:设 \(f_{i,j,0/1}\) 表示考虑到了第 \(i\) 个段,上个与当前硬币不同面的硬币的位置在哪个段里,还有当前段最后一个硬币的正反。

正为 \(1\),反为 \(0\)

则易得出转移方程。

在这段里全部填 \(0\)

\[f_{i,j,0} \to f_{i + 1,j, 0} \]

\[f_{i,j,1}\to f_{i+1,i,0} \]

全部添 \(1\)

\[f_{i,j,1}\to f_{i+1,j,1} \]

\[f_{i,j,0} \to f_{i+1,i,1} \]

\(0,1\) 混杂,此处之所以要减一是因为你要固定最后一个的正反:

\[(2^{len-1}-1)f_{i,j,0/1}\to f_{i+1,i+1,1} \]

\[(2^{len-1} - 1)f_{i,j,0/1} \to f_{i+1,i+1, 0} \]

注意由于要考虑限制:如果不考虑离散化则,在 \([l,r]\) 内至少有一个 \(1\),此时考虑到第 \(i\) 个硬币,则 \(f_{r,i,0}\space(i<l)\) 是不合法的,应置为 \(0\)

而离散化之后小于不好刻画,故我们考虑把 \(l-1\) 扔进去离散化而不是 \(l\)

这样条件就能刻画为:对于每个状态 \(f_{r,i,0} \space (i \le l-1)\) 算完之后我们将其清零。

注意到由于只有在 \(f_i\)\(f_{i+1}\) 之间转移,我们滚动数组。

滚完之后发现,除了清零之外,改变的位置个数是 \(O(1)\) 的,即 \(f_{i+1,0/1}\)\(f_{i,0/1}\)

而在这些的转移式中所有的 \(j\) 它们都会产生固定 \(1\)\((2^{len-1} - 1)\) 的贡献。

这启发我们维护当前 \(f_{*,0}\) 的和与 \(f_{*,1}\) 的和。

每次将对应的贡献乘上总和加上去集合。

于是除了清零之外的操作我们都能在 \(O((n+m)\log k+(n+m)\log (n+m))\) 的时间内解决了。

那清零怎么办呢?

由于只有 \(f\) 的后边会发生变化,前边的变化只有清零,因此一个格子如果被清零它就彻底没戏了。

于是我们记录 \(f_{*,0/1}\) 的两个指针指向当前数组中第一个非零,如果要清空更多零暴力移指针就行了。

因为每清一个零指针就向后一格,而指针单调向后走所以均摊复杂度 \(O(n+m)\)

于是我们就做完了。

小细节:

  • 初始条件是 \(f_{0,0/1}=1\)
  • 离散化的时候要把 \(0,k\) 加入,因为他们是 DP 的起点与终点。
  • 输出答案的时候要除以 \(2\),因为你多算了 \(0\) 号硬币的正反但压根就不存在 \(0\) 号硬币。
#include <bits/stdc++.h>
using namespace std;#define int long long
#define endl '\n'
#define debug(x) cerr << #x << " = " << x << endl
#define rep(i, a, b) for (int i = (a); i <= (b); i++)
#define per(i, a, b) for (int i = (a); i >= (b); i--)
#define gn(u, v) for (int v : G.G[u])
#define pb emplace_back
#define mp make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define pii pair<int, int>
#define vi vector<int>
#define vpii vector<pii>
#define vvi vector<vi>
#define no cout << "NO" << endl
#define yes cout << "YES" << endl
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
#define tomin(x, y) ((x) = min((x), (y)))
#define tomax(x, y) ((x) = max((x), (y)))
#define ck(mask, i) (((mask) >> (i)) & 1)
#define pq priority_queue
#define umap unordered_map
#define FLG (cerr << "Alive!" << endl);constexpr int MAXN = 5e5 + 5;
constexpr int MOD = 1e9 + 7;
int k, n, m;
int l[MAXN], r[MAXN], sum[2], f[MAXN][2];
int c[MAXN], tot;int chk[2][MAXN], tic[2] = { -1, -1 };int qpow(int x, int y) {if (y < 0) return 0;int ans = 1;while (y) {if (y & 1)ans = ans * x % MOD;x = x * x % MOD;y >>= 1;}return ans;
}signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cin >> k >> n >> m;rep (i, 1, n + m) {cin >> l[i] >> r[i];l[i]--;c[++tot] = l[i];c[++tot] = r[i];}c[++tot] = 0;c[++tot] = k;sort(c + 1, c + tot + 1);tot = unique(c + 1, c + tot + 1) - c - 1;rep (i, 1, n + m) {l[i] = lower_bound(c + 1, c + tot + 1, l[i]) - c;r[i] = lower_bound(c + 1, c + tot + 1, r[i]) - c;}memset(chk, 0xff, sizeof chk);rep (i, 1, n)tomax(chk[0][r[i]], l[i]);rep (i, n + 1, n + m)tomax(chk[1][r[i]], l[i]);f[0][0] = f[0][1] = 1;int sum[2] = { 1, 1 };rep (i, 1, tot - 1) {(f[i][0] += sum[1]) %= MOD;(f[i][1] += sum[0]) %= MOD;int cur;if (c[i + 1] - c[i] == 1) cur = 0;else (cur = qpow(2, c[i + 1] - c[i] - 1) + MOD - 1) %= MOD;(cur *= sum[0] + sum[1]) %= MOD;(f[i + 1][0] += cur) %= MOD;(f[i + 1][1] += cur) %= MOD;sum[0] = sum[1] = (sum[0] + sum[1]) % MOD;(sum[0] += cur) %= MOD;(sum[1] += cur) %= MOD;while (tic[0] < chk[0][i + 1]) {tic[0]++;(sum[0] += MOD - f[tic[0]][0]) %= MOD;}while (tic[1] < chk[1][i + 1]) {tic[1]++;(sum[1] += MOD - f[tic[1]][1]) %= MOD;}}cout << (sum[0] + sum[1]) * (MOD + 1) / 2 % MOD << endl;return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/884294.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

P1121 环状最大两段子段和

链接 https://www.luogu.com.cn/problem/P1121 题目思路这个O(n)的思路很好:https://www.cnblogs.com/kamimxr/p/11438701.html。 关键思路: 答案分两种情况,一种是选择的两段均不跨越n到1(也就是环),另一种是选择的两段跨过了环; 如果均不跨越环,那么也就是意味着这是一道…

muduo网络库核心代码阅读(Thread,EventLoopThread,EventLoopThreadPool)(4)

muduo网络库核心设计为one loop one thread,即一个线程一个事件循环。其中,主Reactor负责监听新连接,并将新连接平均分配到从Reactor中,而从Reactor则对分配到其上的用户进行io交互,接收并处理用户发来的数据,包括消息的回复(实际上,在使用中需要手动设置Reactor线程的…

C#生成多尺寸bmp格式ICO图标代码

代码取自deepseek,且已经过本地执行测试 //.cs 文件类型,便于外部编辑时使用 // 引用必要的命名空间 using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Runtime.InteropServices;/…

CTA:回测执行引擎BacktestingEngine

回测执行引擎BacktestingEngine 回顾前面的文章CTA:回测综述,那里提到,真正执行回测的逻辑,写在BacktestingEngine中。 代码解读 BacktestingEngine定义在vnpy_ctastrategy -> backtesting.py中。 package from collections import defaultdict from datetime import da…

CTA:回测快速示例

设置工作目录 VNPY程序启动后,会产生一个工作目录,程序运行产生的数据、系统配置都会放在指定的.vntrader目录当中。 这一设置在vnpy -> utility.py -> _get_trader_dir函数中可以找到,工作目录由TRADER_DIR, TEMP_DIR确定。 def _get_trader_dir(temp_name: str) -&g…

VNPY体系结构

整体架构每个层次的模块只调用下层功能,并对上层提供接口。接口层负责对接行情和交易API,将行情数据推送到系统,发送交易指令。 引擎层向下对接交易接口、数据库,向上服务于各种上层应用。 应用层主要是面向用户的可视化界面,这一部分的代码主要为引擎功能与界面的连接。功…

【ABP】项目示例(2)——聚合根和实体

聚合根和实体 在上一章节中,已经完成了项目搭建的前置准备,在这一章节中,实现领域层的聚合根和实体 创建名称为General.Backend.Domain的标准类库,分别新建名称为Entities、Services、IRepositories和Specifications的文件夹,用于存放实体和聚合根、领域服务、仓储接口和规…

P1896 [SCOI2005] 互不侵犯(状态压缩)

位运算符好麻烦,没打括号被卡了半天 #include<iostream> #define int long long using namespace std; int f[12][100][1<<11]; int s[1<<11]; int num[1<<11]; signed main(){int n,k;cin>>n>>k;int cnt=0;for(int i=0;i<(1<<…

200N03-ASEMI豆浆机专用MOS管200N03

200N03-ASEMI豆浆机专用MOS管200N03编辑:ll 200N03-ASEMI豆浆机专用MOS管200N03 型号:200N03 品牌:ASEMI 封装:TO-252 批号:最新 最大漏源电流:200A 漏源击穿电压:30V RDS(ON)Max:1.8mΩ 引脚数量:3 芯片个数: 沟道类型:N沟道MOS管、中低压MOS管 漏电流:ua 特性:…

第七章-收益归因:Brinson模型

例子 现有一个投资组合,其基准组合为:70%中证800,20%债券,10%现金,如下:基金经理主动投资,对资产权重进行调整。假设基准组合收益率为\(r\)。若是看好股票,那就多配置一些股票,调整中证800权重为\(w_1^{\prime}\)。则收益调整为(\(w_1^{\prime}-w)(r_1-r)\)。会有两种情…