【10.11校内测试】【优先队列(反悔贪心)】【莫队】【stl的应用??离线处理+二分】

上次做过类似的题,原来这道还要简单些??
上次那道题是每天可以同时买进卖出,所以用两个优先队列,一个存买进,一个存卖出(供反悔的队列)。
这道题实际上用一个就够了???但是不好理解!!
所以我还是用了俩...
和之前那道题不同的是,如果我选择了反悔,之前第二个队列的队头就完全没有用了,但是我们可以选择重新买它,所以把它重新放到第一个队列。
#include<bits/stdc++.h>
using namespace std; priority_queue < int, vector < int >, greater < int > > q1, q2; int n, a[];
long long ans; int main() {
freopen("trade.in", "r", stdin);
freopen("trade.out", "w", stdout);
scanf("%d", &n);
for(int i = ; i <= n; i ++) scanf("%d", &a[i]);
for(int i = ; i <= n; i ++) {
int x1, x2, r1 = , r2 = ;
if(!q1.empty()) {
x1 = q1.top(); if(a[i] - x1 > ) r1 = a[i] - x1;
}
if(!q2.empty()) {
x2 = q2.top(); if(a[i] - x2 > ) r2 = a[i] - x2;
}
if(r1 >= r2 && r1) {
q1.pop(); q2.push(a[i]); ans += r1;
} else if(r2 > r1 && r2 ) {
q2.pop(); q2.push(a[i]); q1.push(x2); ans += r2;
} else q1.push(a[i]);
}
printf("%lld", ans);
return ;
}

这道题乍一看是推公式$O(1)$的数论??经$yuli$dalao考场上一个多小时的测试发现没有这样的式子....
所以$zc$dalao通过研究打表发现了正解!其实是莫队!
???
首先我们也来打一下表....发现了两个递推式:$S_n^m=S_n^{m-1}+C_n^m$和$S_n^m=2S_{n-1}^m-C_{n-1}^m$,我们可以把$[n,m]$看成一个区间来进行离线莫队转移,复杂度$O(n\sqrt{n})$。
#include<bits/stdc++.h>
#define mod 1000000007
#define LL long long
using namespace std; int blo[]; struct Node {
int n, m, id;
} qus[];
bool cmp(Node a, Node b) { if(blo[a.m] == blo[b.m]) return a.n < b.n; return a.m < b.m; } LL fac[], inv[];
LL C(int n, int m) {
if(m > n) return ;
return fac[n] * inv[m] % mod * inv[n - m] % mod;
} LL mpow(LL a, LL b) {
LL ans = ;
for(; b; b >>= , a = a * a % mod)
if(b & ) ans = ans * a % mod;
return ans;
} void init() {
fac[] = ; inv[] = , inv[] = ;
for(int i = ; i <= ; i ++)
fac[i] = fac[i - ] * i % mod;
for(int i = ; i <= ; i ++)
inv[i] = mpow(fac[i], mod - );
for(int i = ; i <= ; i ++) blo[i] = i/ + ;
} int Ans[];
int main() {
freopen("sum.in", "r", stdin);
freopen("sum.out", "w", stdout);
int id;
scanf("%d", &id);
init();
int T;
scanf("%d", &T);
for(int i = ; i <= T; i ++)
scanf("%d%d", &qus[i].n, &qus[i].m), qus[i].id = i;
sort(qus + , qus + + T, cmp); int n = qus[].n, m = qus[].m; LL ans = ;
for(int i = ; i <= m; i ++) ans = (ans + C(n, i)) % mod;
Ans[qus[].id] = ans;
for(int i = ; i <= T; i ++) {
while(qus[i].m < m) {
ans = (ans - C(n, m) + mod) % mod;
m --;
}
while(qus[i].n > n) {
ans = (2LL * ans % mod - C(n, m) + mod) % mod;
n ++;
}
while(qus[i].m > m) {
m ++;
ans = (ans + C(n, m)) % mod;
}
while(qus[i].n < n) {
n --;
ans = 1LL * (ans + C(n, m)) * inv[] % mod;
}
Ans[qus[i].id] = ans;
}
for(int i = ; i <= T; i ++) printf("%d\n", Ans[i]);
return ;
}


感觉这种题就算让我再做一次,也写不出来...重载什么的简直太难记了aaa!!
对于第一个询问,直接分别处理每行和每列就行了,每行就直接加,每列用差分处理。
如何查找联通块数量?
分别处理两种情况:
1)与下边相交
对于上面的矩形,查找它下一排最后一个与它相交的矩形,向前枚举直到不相交,把相交的矩形连边。
2)与右边相交
对于左边的矩形,查找它右边与它相交的所有矩形,连边。
以上操作用二分实现。注意的是,因为我们建边是在每排的基础上(因为查询的是排),所以第一种应该建在下面那排,第二种应该建在两个矩形上边界的排取max。(查询前缀时才能保证合法)
stl(vector简直tql!QAQ)
#include<bits/stdc++.h>
#define LL long long
using namespace std; int ans2[];
LL ans1[], sum2[], sum1[]; struct Data {
int lx, ly, rx, ry;
Data(int lx = , int ly = , int rx = , int ry = ) :
lx(lx), ly(ly), rx(rx), ry(ry) { }
} A[]; struct Node {
int id, l, r;
Node(int id = , int l = , int r = ) :
id(id), l(l), r(r) { }
}; vector < Node > row[], col[];
bool operator < (const Node &a, const Node &b) {
return a.l < b.l || (a.l == b.l && a.r < b.r);
} vector < pair < int , int > > G[]; int root[], edge, num;
int find(int x) {
if(root[x] != x) root[x] = find(root[x]);
return root[x];
} void merge(int x, int y) {
x = find(x); y = find(y);
if(x != y) root[x] = y, ++ edge;
} int main() {
freopen("building.in", "r", stdin);
freopen("building.out", "w", stdout);
int opt;
scanf("%d", &opt);
int n, m, k, p;
scanf("%d%d%d%d", &n, &m, &k, &p);
for(int i = ; i <= k; i ++) {
int lx, ly, rx, ry;
scanf("%d%d%d%d", &lx, &ly, &rx, &ry);
A[i] = Data(lx, ly, rx, ry);
row[lx].push_back(Node(i, ly, ry));
col[ly].push_back(Node(i, lx, rx));
if(lx == rx) sum1[lx] += (ry - ly + );
else sum2[lx] ++, sum2[rx + ] --;
}
for(int i = ; i <= n; i ++) sort(row[i].begin(), row[i].end());
for(int i = ; i <= m; i ++) sort(col[i].begin(), col[i].end());
for(int i = ; i <= k; i ++) {
int down = A[i].rx + ;
if(down <= n && row[down].size()) {
int p = upper_bound(row[down].begin(), row[down].end(), Node(, A[i].ry, m + )) - row[down].begin() - ;
for(; p >= && row[down][p].r >= A[i].ly; p --)
G[down].push_back(make_pair(i, row[down][p].id));
}
int right = A[i].ry + ;
if(right <= m && col[right].size()) {
if(right < ) return ;
int p = upper_bound(col[right].begin(), col[right].end(), Node(, A[i].rx, n + )) - col[right].begin() - ;
for(; p >= && col[right][p].r >= A[i].lx; p --)
G[max(A[i].lx, A[col[right][p].id].lx)].push_back(make_pair(i, col[right][p].id));
}
}
for(int i = ; i <= n; i ++) sum2[i] += sum2[i-];
for(int i = ; i <= n; i ++) {
sum2[i] += sum2[i-];
sum1[i] += sum1[i-];
ans1[i] = sum1[i] + sum2[i];
}
for(int i = ; i <= k; i ++) root[i] = i;
for(int i = ; i <= n; i ++) {
num += row[i].size();
for(int j = ; j < G[i].size(); j ++) merge(G[i][j].first, G[i][j].second);
ans2[i] = num - edge;
}
while(p --) {
int u, v;
scanf("%d%d", &u, &v);
if(u) printf("%d\n", ans2[v]);
else printf("%lld\n", ans1[v]);
}
return ;
}
【10.11校内测试】【优先队列(反悔贪心)】【莫队】【stl的应用??离线处理+二分】的更多相关文章
- 【8.30校内测试】【找规律模拟】【DP】【二分+贪心】
对于和规律或者数学有关的题真的束手无策啊QAQ 首先发现两个性质: 1.不管中间怎么碰撞,所有蚂蚁的相对位置不会改变,即后面的蚂蚁不会超过前面的蚂蚁或者落后更后面的蚂蚁. 2.因为所有蚂蚁速度一样,不 ...
- 2018.10.29 bzoj4564: [Haoi2016]地图(仙人掌+莫队)
传送门 根据原图建一棵新的树. 把原图每一个环上除了深度最浅的点以外的点全部向深度最浅的点连边. 然后可以搞出来一个dfsdfsdfs. 这个时候我们就成功把问题转换成了对子树的询问. 然后就可以对权 ...
- [CSP-S模拟测试]:sum(数学+莫队)
题目传送门(内部题63) 输入格式 第一行有一个整数$id$,表示测试点编号.第一行有一个整数$q$,表示询问组数.然后有$q$行,每行有两个整数$n_i,m_i$. 输出格式 一共有$q$行,每行一 ...
- [CSP-S模拟测试]:飘雪圣域(莫队)
题目描述 $IcePrincess\text{_}1968$和$IcePrince\text{_}1968$长大了,他们开始协助国王$IceKing\text{_}1968$管理国内事物. $IceP ...
- 联赛模拟测试12 C. sum 莫队+组合数
题目描述 分析 \(80\) 分的暴力都打出来了还是没有想到莫队 首先对于 \(s[n][m]\) 我们可以很快地由它推到 \(s[n][m+1]\) 和 \(s[n][m-1]\) 即 \(s[n] ...
- SPOJ DQUERY - D-query (莫队算法|主席树|离线树状数组)
DQUERY - D-query Given a sequence of n numbers a1, a2, ..., an and a number of d-queries. A d-query ...
- 【11.5校内测试】【倒计时5天】【DP】【二分+贪心check】【推式子化简+线段树】
Solution 非常巧妙的建立DP方程. 据dalao们说题目明显暗示根号复杂度??(反正我是没看出来 因为每次分的块大小一定不超过$\sqrt n$,要不然直接每个位置开一个块答案都才为$n$. ...
- 【10.7校内测试】【队列滑窗】【2-sat】【贪心+栈二分+线段树(noip模拟好题)】【生日祭!】
比较好想的一道题,直接用队列滑窗,因为扫一遍往队列里加东西时,改变的只有一个值,开桶储存好就行了! #include<bits/stdc++.h> using namespace std; ...
- 【10.17校内测试】【二进制数位DP】【博弈论/预处理】【玄学(?)DP】
Solution 几乎是秒想到的水题叻! 异或很容易想到每一位单独做贡献,所以我们需要统计的是区间内每一位上做的贡献,就是统计区间内每一位是1的数的数量. 所以就写数位dp辣!(昨天才做了数字统计不要 ...
随机推荐
- 【FCS NOI2018】福建省冬摸鱼笔记 day5
第五天,也是讲课的最后一天. 数据结构专题,讲师:杨志灿 他的blog我似乎找不到了……以前肯定是在百度博客里面.但是现在百度博客消失了. PPT做的很有感觉,说了很多实用的技巧. 我觉得其实是收获最 ...
- 10 The Go Programming Language Specification go语言规范 重点
The Go Programming Language Specification go语言规范 Version of May 9, 2018 Introduction 介绍 Notation 符号 ...
- 用js面向对象思想封装插件
js是基于原型的面向对象语言,如果你学过java,c#等正统面向对象语言,你会难以理解js的面向对象,他和普通的面向对象不太一样,今天,我们通过封装一个toast插件,来看看js面向对象是如何运行的. ...
- 签名DLL
签名DLL 首先需要一个密钥文件,后缀为.snk 密钥文件使用sn.exe 创建: sn.exe /k MySingInKey.snk sn.exe 工具的具体使用,可以通过 sn.exe /h 或 ...
- Codeforces 734C Anton and Making Potions(枚举+二分)
题目链接:http://codeforces.com/problemset/problem/734/C 题目大意:要制作n个药,初始制作一个药的时间为x,魔力值为s,有两类咒语,第一类周瑜有m种,每种 ...
- Effective STL 学习笔记 Item 26: Prefer Iterator to reverse_iterator and const_rever_itertor
Effective STL 学习笔记 Item 26: Prefer Iterator to reverse_iterator and const_rever_itertor */--> div ...
- SqlServer性能优化 Sql语句优化(十四)
一:在较小的结果集上上操作 1.仅返回需要的列 2.分页获取数据 EF实现分页: public object getcp(int skiprows,int currentpagerows) { HRU ...
- NOIP2015&2016普及组解题报告
NOIP2015普及组题目下载 NOIP2016普及组题目下载 NOIP2015普及组题目: NOIP2018RP++ NOIP2016普及组题目 NOIP2018RP++ T1 金币\((coin. ...
- WinForm界面开发之 启动界面
我们在开发桌面应用程序的时候,由于程序启动比较慢,往往为了提高用户的体验,增加一个闪屏,也就是SplashScreen,好处有:1.让用户看到加载的过程,提高程序的交互响应:2.可以简短展示或者介绍程 ...
- hdu 1760 DFS+博弈
0代表可放 1带表不能放 每次放一个2*2的方块 不能放者败如果先手必胜则输出Yes 必胜态:从当前状态所能到达的状态中存在一个必败态必败态:从当前状态所能达到的状态全部是必胜态 Sample Inp ...