【11.5校内测试】【倒计时5天】【DP】【二分+贪心check】【推式子化简+线段树】


Solution
非常巧妙的建立DP方程。
据dalao们说题目明显暗示根号复杂度??(反正我是没看出来
因为每次分的块大小一定不超过$\sqrt n$,要不然直接每个位置开一个块答案都才为$n$。
于是大佬们想到用一个非常巧妙的数组$pos[j]$,表示顺推到当前位置$i$时,以$i$作为右端点,区间出现了$j$个颜色的左端点的位置。
于是每次转移就变成了$dp[i]=min(dp[pos[j]-1]+j*j)$,而不需要把之前全部枚举。$j$的范围就是$<=\sqrt n$的。
所以每次新到一个位置,就对于每个$j$看是否有新的贡献,记录$cnt[j]$表示$pos[j]$到$i$当前实际有多少个颜色。
如果$cnt[j]>j$表示当前$pos[j]$需要往后移动更新,那么每次往后一位一位暴力移动查询当前位置是否可以作为$pos[j]$,就是判断这个位置之后,$i$之前是否还出现了这个位置的颜色,如果出现了那么这个位置就不能作为$pos[j]$,因为它后面还有贡献。(据说均摊复杂度O(n)??)
细节通过双向链表处理。
Code
#include<bits/stdc++.h>
#define LL long long
#define RG register
using namespace std; LL dp[];
int nxt[], a[], pre[], las[], pos[], cnt[];
int n, m; int main() {
freopen("cleanup.in", "r", stdin);
freopen("cleanup.out", "w", stdout);
scanf("%d%d", &n, &m);
for(int i = ; i <= n; i ++) {
scanf("%d", &a[i]);
pre[i] = las[a[i]];
nxt[las[a[i]]] = i;
las[a[i]] = i;
nxt[i] = n + ;
}
memset(dp, 0x3f3f3f3f, sizeof(dp)); dp[] = ;
int siz = sqrt(n); for(int i = ; i <= siz; i ++) pos[i] = ;
for(RG int i = ; i <= n; i ++) {
for(RG int j = ; j <= siz; j ++) {
if(pre[i] < pos[j]) cnt[j] ++;
if(cnt[j] > j) {
cnt[j] --;
while(nxt[pos[j]] < i) pos[j] ++;
pos[j] ++;
}
dp[i] = min(dp[pos[j] - ] + j * j, dp[i]);
}
}
printf("%lld", dp[n]);
return ;
}


Solution
二分性很明显,但是check竟然是用搜索回溯处理???真实震惊
搜索大概就是每次在剩下没有被覆盖的点中找到最靠左、最靠右、最靠下、最靠上四个极点位置,然后每次贪心往四个角(左上、左下、右上、右下)填矩阵,更新剩下没覆盖的点,搜三层回来即可.....
真的好玄学啊QAQ但是就是过了QAQ
Code
#include<bits/stdc++.h>
#define oo 0x3f3f3f3f
#define LL long long
using namespace std; int n, xmi, xma, ymi, yma, MA; struct Node {
LL x, y;
} tr[];
bool cmp1(Node a, Node b) { return a.x < b.x; }
bool cmp2(Node a, Node b) { return a.y < b.y; } bool flag, vis[];
LL now; void dfs(int dep, int tot) {
if(tot == n) { flag = ; return ; }
if(dep == ) return ;
bool used[] = {};
LL maxx = -oo, minx = oo, maxy = -oo, miny = oo;
for(int i = ; i <= n; i ++) {
if(vis[i]) continue;
maxx = max(maxx, tr[i].x); minx = min(minx, tr[i].x);
maxy = max(maxy, tr[i].y); miny = min(miny, tr[i].y);
} int cnt = ; LL xl = minx, xr = minx + now, yl = miny, yr = miny + now; cnt = ;
for(int i = ; i <= n; i ++) {
if(vis[i]) continue;
if(tr[i].x <= xr && tr[i].x >= xl && tr[i].y >= yl && tr[i].y <= yr) {
vis[i] = ; used[i] = ; cnt ++;
}
}
dfs(dep + , tot + cnt); if(flag) return ;
for(int i = ; i <= n; i ++) if(used[i]) vis[i] = used[i] = ; xl = minx, xr = minx + now, yl = maxy - now, yr = maxy; cnt = ;
for(int i = ; i <= n; i ++) {
if(vis[i]) continue;
if(tr[i].x <= xr && tr[i].x >= xl && tr[i].y >= yl && tr[i].y <= yr) {
vis[i] = ; used[i] = ; cnt ++;
}
}
dfs(dep + , tot + cnt); if(flag) return ;
for(int i = ; i <= n; i ++) if(used[i]) vis[i] = used[i] = ; xl = maxx - now, xr = maxx, yl = maxy - now, yr = maxy; cnt = ;
for(int i = ; i <= n; i ++) {
if(vis[i]) continue;
if(tr[i].x <= xr && tr[i].x >= xl && tr[i].y >= yl && tr[i].y <= yr) {
vis[i] = ; used[i] = ; cnt ++;
}
}
dfs(dep + , tot + cnt); if(flag) return ;
for(int i = ; i <= n; i ++) if(used[i]) vis[i] = used[i] = ; xl = maxx - now, xr = maxx, yl = miny, yr = miny + now; cnt = ;
for(int i = ; i <= n; i ++) {
if(vis[i]) continue;
if(tr[i].x <= xr && tr[i].x >= xl && tr[i].y >= yl && tr[i].y <= yr) {
vis[i] = ; used[i] = ; cnt ++;
}
}
dfs(dep + , tot + cnt); if(flag) return ;
for(int i = ; i <= n; i ++) if(used[i]) vis[i] = used[i] = ;
} bool check(LL mid) {
now = mid; flag = ;
for(int i = ; i <= n; i ++) vis[i] = ;
dfs(, );
return flag;
} LL erfen() {
LL l = , r = , ans;
while(l <= r) {
LL mid = (l + r) >> ;
if(check(mid)) ans = mid, r = mid - ;
else l = mid + ;
}
return ans;
} int main() {
freopen("cover.in", "r", stdin);
freopen("cover.out", "w", stdout);
scanf("%d", &n);
for(int i = ; i <= n; i ++)
scanf("%lld%lld", &tr[i].x, &tr[i].y);
LL ans = erfen();
printf("%lld", ans);
return ;
}


Solution
区间修改??发现没那么简单QAQ,是求多个区间的和,没办法直接修改就快速求出答案。
所以推一推式子将$n^3$优化到$n^2$,要求的区间的区间和实际上可以由每条边的贡献算出来:$\sum_{i=L}^{R}{v[i]*(i-L+1)*(R-i+1)}$,此处$R$是事先$--$了的,因为$R-R+1$的边不能被算入贡献。
化简得$\sum{iv[i] * (L + R) - i^2v[i] + v[i] * (R - L * R + 1 - L)}$所以要维护的变量实际上只有$iv[i].i^2v[i].v[i]$三个的区间和即可,用一颗线段树结构体就好辣。
全都要开longlong才可以!!
Code
#include<bits/stdc++.h>
#define LL long long
using namespace std; LL n, m; LL gcd(LL a, LL b) {
return b == ? a : gcd(b, a % b);
} struct Node {
LL iv, v, iv2;
Node operator + (const Node &a) const {
Node c;
c.iv = iv + a.iv; c.v = v + a.v; c.iv2 = iv2 + a.iv2;
return c;
}
} TR[]; LL tag[], iv[], iv2[]; void push_down(LL nd, LL l, LL r) {
if(tag[nd]) {
LL d = tag[nd], mid = (l + r) >> ;
TR[nd << ].iv += d * (iv[mid] - iv[l - ]);
TR[nd << ].iv2 += d * (iv2[mid] - iv2[l - ]);
TR[nd << ].v += d * (mid - l + );
TR[nd << | ].iv += d * (iv[r] - iv[mid]);
TR[nd << | ].iv2 += d * (iv2[r] - iv2[mid]);
TR[nd << | ].v += d * (r - mid);
tag[nd << ] += d, tag[nd << | ] += d; tag[nd] = ;
}
} void update(LL nd) {
TR[nd] = TR[nd << ] + TR[nd << | ];
} void modify(LL nd, LL l, LL r, LL L, LL R, LL d) {
if(l >= L && r <= R) {
TR[nd].iv += d * (iv[r] - iv[l - ]);
TR[nd].iv2 += d * (iv2[r] - iv2[l - ]);
TR[nd].v += d * (r - l + );
tag[nd] += d;
return ;
}
push_down(nd, l, r); LL mid = (l + r) >> ;
if(L <= mid) modify(nd << , l, mid, L, R, d);
if(R > mid) modify(nd << | , mid + , r, L, R, d);
update(nd);
} Node query(LL nd, LL l, LL r, LL L, LL R) {
if(l >= L && r <= R) return TR[nd];
push_down(nd, l, r);
LL mid = (l + r) >> ; Node ans; ans.iv = ans.iv2 = ans.v = ;
if(L <= mid) ans = ans + query(nd << , l, mid, L, R);
if(R > mid) ans = ans + query(nd << | , mid + , r, L, R);
return ans;
} void init() {
for(LL i = ; i <= n; i ++) {
iv[i] = iv[i - ] + i;
iv2[i] = iv2[i - ] + i * i;
}
} int main() {
freopen("roadxw.in", "r", stdin);
freopen("roadxw.out", "w", stdout);
scanf("%lld%lld", &n, &m);
init();
for(LL t = ; t <= m; t ++) {
char s[]; LL L, R, V;
scanf("%s", s);
if(s[] == 'C') {
scanf("%lld%lld%lld", &L, &R, &V);
modify(, , n, L, R - , V);
} else {
scanf("%lld%lld", &L, &R);
R --;
Node a = query(, , n, L, R);
LL ans = a.iv * (L + R) - a.iv2 + a.v * (R - L * R + - L);
LL tot = R - L + ;
LL ans2 = tot * (tot - ) / ;
LL d = gcd(ans, ans2);
ans /= d, ans2 /= d;
printf("%lld/%lld\n", ans, ans2);
}
}
return ;
}
【11.5校内测试】【倒计时5天】【DP】【二分+贪心check】【推式子化简+线段树】的更多相关文章
- Codeforces Round #442 (Div. 2)A,B,C,D,E(STL,dp,贪心,bfs,dfs序+线段树)
A. Alex and broken contest time limit per test 2 seconds memory limit per test 256 megabytes input s ...
- “盛大游戏杯”第15届上海大学程序设计联赛夏季赛暨上海高校金马五校赛题解&&源码【A,水,B,水,C,水,D,快速幂,E,优先队列,F,暴力,G,贪心+排序,H,STL乱搞,I,尼姆博弈,J,差分dp,K,二分+排序,L,矩阵快速幂,M,线段树区间更新+Lazy思想,N,超级快速幂+扩展欧里几德,O,BFS】
黑白图像直方图 发布时间: 2017年7月9日 18:30 最后更新: 2017年7月10日 21:08 时间限制: 1000ms 内存限制: 128M 描述 在一个矩形的灰度图像上,每个 ...
- 【11.8校内测试】【倒计时2天】【状压DP】【随机化?/暴力小模拟】
Solution 数据范围疯狂暗示状压,可是一开始发现状态特别难受. 将每一层的奇偶性状压,预处理所有状态的奇偶性.每一层的输入代表的其实可以是下一层某个点可以被从这一层哪些点转移到. 所以枚举每个状 ...
- 【11.9校内测试】【倒计时1天】【ak欢乐赛】【多项式计算模拟】
然而AK失败了,就是因为这道摸你题:(最后一篇题解了吧?QAQ) Solution 模拟多项式乘法,其中的运算处理很像高精度,不过第$i$位代表的就是$x^i$前面的系数了. 好像去年的时候就讲了表达 ...
- 【11.1校内测试】【快速幂DP】【带权并查集】【模拟】
Solution $jzy$大佬用了给的原根的信息,加上矩阵快速幂150行QAQ 然而$yuli$大佬的做法不仅好懂,代码只有50行! 快速幂的思想,把m看成要组成的区间总长度,每次将两段组合得到新的 ...
- 【8.31校内测试】【找规律二分】【DP】【背包+spfa】
打表出奇迹!表打出来发现了神奇的规律: 1 1 2 2 3 4 4 4 5 6 6 7 8 8 8 8 9 10 10 11 12 12 12 13 14 14 15 16 16 16 16 16.. ...
- 【10.11校内测试】【优先队列(反悔贪心)】【莫队】【stl的应用??离线处理+二分】
上次做过类似的题,原来这道还要简单些?? 上次那道题是每天可以同时买进卖出,所以用两个优先队列,一个存买进,一个存卖出(供反悔的队列). 这道题实际上用一个就够了???但是不好理解!! 所以我还是用了 ...
- 【10.4校内测试】【轮廓线DP】【中国剩余定理】【Trie树+博弈】
考场上几乎是一看就看出来轮廓线叻...可是调了两个小时打死也过不了手出样例!std发下来一对,特判对的啊,转移对的啊,$dp$数组竟然没有取max!!! 某位考生当场死亡. 结果下午又请了诸位dala ...
- 【8.28校内测试】【区间DP】
感受到了生活的艰辛QAQ...这才是真正的爆锤啊...(因为t1t3还没有理解所以只能贴t2叻QAQ 区间DP...爆哭把题理解错了,以为随着拿的东西越来越多,断点也会越来越多,出现可以选很多的情况Q ...
随机推荐
- ES系列十九、kibana基本查询、可视化、仪表盘用法
一. 定义索引模式匹配 1.前缀模糊匹配,一个模式匹配多个索引 每一个数据集导入到Elasticsearch后会有一个索引匹配模式,在上段内容莎士比亚数据集有一个索引名称为shakespeare,账户 ...
- shell编程之helloworld
/bin/sh与/bin/bash的区别sh:如果前面有语句报错,则报错语句后面的命令不执行bash:如果前面有语句报错,后面的命令也会执行sh跟bash的区别,实际上就是bash有没有开启posix ...
- VS C# xamarin 开发android 调试正常 发布分发后运行闪退出错
我强烈推荐大家如果不是很有必要就不要引用一些.NET STD的库,比如json库newtonsoft.JSON,直接引用官方的system.Json就足够了,否则会导致体积变得巨大 好了废话不多说,这 ...
- 一张纸,折多少次和珠穆拉峰一样高(for if 和break)
- excel导出的时候从程序后台写到excel里的是文本,所以无法在excel中计算怎么办?
文章引用自:http://www.cnblogs.com/rayray/p/3414452.html excel导出的时候从程序后台写到excel里的是文本,所以无法在excel中计算怎么办? 需要导 ...
- 【C++ Primer | 15】虚继承
虚基类 一.虚基类介绍 多继承时很容易产生命名冲突,即使我们很小心地将所有类中的成员变量和成员函数都命名为不同的名字,命名冲突依然有可能发生,比如非常经典的菱形继承层次.如下图所示: 类A派生出类B和 ...
- vtiger7安装设置
安装界面一直报错 其实是设置的问题 error_reporting:E_WARNING & ~E_NOTICE & ~E_DEPRECATED max_execution_time:6 ...
- BZOJ1567 [JSOI2008]Blue Mary的战役地图 二分答案 哈希
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1567 题意概括 给出两个n*n的数字矩阵,问最大公共正方形边长. 题解 先二分答案一个m,对于每一 ...
- How to cast List<Object> to List<MyClass> Object集合转换成实体集合
List<Object> list = getList(); return (List<Customer>) list; Compiler says: cannot cast ...
- laravel5 项目上线后务必将开发环境更改为生产环境
如果以开发环境上线,出错信息将全通过json暴露出来了,屏蔽方式如下: .env 文件设置如下APP_ENV=productionAPP_DEBUG=false 改完设置后把缓存清理一遍 如果更改后清 ...