【Codeforces】#345 Div1
1. Watchmen
1.1 题目描述
给$n$个点,求曼哈顿距离等于欧式距离的点对数。
1.2 基本思路
由$|x_i-x_j|+|y_i-yj| = \sqrt{(x_i-x_j)^2+(y_i-yj)^2}$可以推出$x_i=x_j$或者$y_i=y_j$。
所以变得超级简单了,排序后对两种情况分别累加即可。
1.3 代码
/* A */
#include <iostream>
#include <sstream>
#include <string>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <vector>
#include <deque>
#include <bitset>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <ctime>
#include <cstring>
#include <climits>
#include <cctype>
#include <cassert>
#include <functional>
#include <iterator>
#include <iomanip>
using namespace std;
//#pragma comment(linker,"/STACK:102400000,1024000") #define sti set<int>
#define stpii set<pair<int, int> >
#define mpii map<int,int>
#define vi vector<int>
#define pii pair<int,int>
#define vpii vector<pair<int,int> >
#define rep(i, a, n) for (int i=a;i<n;++i)
#define per(i, a, n) for (int i=n-1;i>=a;--i)
#define clr clear
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define all(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define lson l, mid, rt<<1
#define rson mid+1, r, rt<<1|1 const int maxn = 2e5+;
int Y[maxn], ny = ;
int c[maxn]; int main() {
ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
freopen("data.in", "r", stdin);
freopen("data.out", "w", stdout);
#endif int n;
int x, y;
vpii vp; scanf("%d", &n);
rep(i, , n) {
scanf("%d%d", &x, &y);
vp.pb(mp(x, y));
Y[i] = y;
} sort(all(vp));
sort(Y, Y+n);
ny = unique(Y, Y+n) - Y; int i = , j;
__int64 ans = ; while (i < n) {
j = i;
while (i<n && vp[i].fir==vp[j].fir) {
vp[i].sec = lower_bound(Y, Y+ny, vp[i].sec) - Y;
ans += c[vp[i].sec];
++i;
}
ans += 1LL * (i-j) * (i-j-) / ;
while (j < i) {
++c[vp[j].sec];
++j;
}
} printf("%I64d\n", ans); #ifndef ONLINE_JUDGE
printf("time = %d.\n", (int)clock());
#endif return ;
}
2. Image Preview
2.1 题目描述
手机上有n张照片,翻看照片仅仅能翻看相邻的照片(1与n相邻),每次翻看花费a秒。
手机一直处于垂直方向,照片可能为水平或垂直方向,当照片与手机方向不同时,需要花费额外b秒旋转。
观看照片需要1秒,同时可以跳过已经看过的照片,没有看过的照片则必须观看。求在时间T内最多观看多少照片。
2.2 基本思路
假设在时间$T$内最多观看$m$张照片,并且移动到没看过的照片必须观看。显然,这$m$个照片必然形成一个连续的区间(假定1与n连续)。
$L[i], R[i]$分别表示从1(起始位置)逆时针和顺时针看过$i$张照片所用的时间。
因此,我们可以对$m$进行二分,判断$\min \{L[k] + R[m-1-k] - T_{skip} - L[1]\} \le T$。这里$T_{skip} = a * \min (k, m-1-k)$。
$L[i], R[i]$可以在$O(n)$时间内预处理,因此时间复杂度为$O(nlogn)$。
2.3 代码
/* B */
#include <iostream>
#include <sstream>
#include <string>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <vector>
#include <deque>
#include <bitset>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <ctime>
#include <cstring>
#include <climits>
#include <cctype>
#include <cassert>
#include <functional>
#include <iterator>
#include <iomanip>
using namespace std;
//#pragma comment(linker,"/STACK:102400000,1024000") #define sti set<int>
#define stpii set<pair<int, int> >
#define mpii map<int,int>
#define vi vector<int>
#define pii pair<int,int>
#define vpii vector<pair<int,int> >
#define rep(i, a, n) for (int i=a;i<n;++i)
#define per(i, a, n) for (int i=n-1;i>=a;--i)
#define clr clear
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define all(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define lson l, mid, rt<<1
#define rson mid+1, r, rt<<1|1 const int maxn = 5e5+;
int n, a, b, T;
char s[maxn];
int L[maxn], R[maxn]; bool judge(int m) {
int mn = INT_MAX, tmp; --m;
for (int ln=m,rn=; ln>=; --ln,++rn) {
tmp = L[ln] + R[rn] -L[] + min(ln, rn) * a;
mn = min(tmp, mn);
} return mn<=T;
} void solve() {
R[] = s[]=='w' ? b+:;
rep(i, , n) {
R[i] += R[i-];
R[i] += a + ;
if (s[i] == 'w')
R[i] += b;
}
L[] = s[]=='w' ? b+:;
rep(i, , n) {
L[i] += L[i-];
L[i] += a + ;
if (s[n-i] == 'w')
L[i] += b;
} if (T < R[]) {
puts("");
return ;
} int l = ;
int r = n;
int mid;
int ans = ; while (l <= r) {
mid = (l + r) >> ;
if (judge(mid)) {
ans = mid;
l = mid + ;
} else {
r = mid - ;
}
} printf("%d\n", ans);
} int main() {
ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
freopen("data.in", "r", stdin);
freopen("data.out", "w", stdout);
#endif scanf("%d%d%d%d", &n,&a,&b,&T);
scanf("%s", s);
solve(); #ifndef ONLINE_JUDGE
printf("time = %d.\n", (int)clock());
#endif return ;
}
3. Table Compression
3.1 题目描述
将矩阵$A_{n \times m}$压缩成$B_{n \times m}, b_ij > 0$。
同时,$\forall a_ij,a_ik$中的大小关系与$B$中对应元素保持一致,$\forall a_ij,a_kj$同样保持一致。
找到这样一个$B$,并是$B$中的最大值最小。
3.2 基本思路
先考虑$A$中的元素均不相同,那么显然可以建立一个有向图(较小值指向较大值),然后进行拓扑。
然而$n \cdot m \le 10^6$,这也导致了这样朴素建图边会超多$10^9$左右。
那么,能不能减少一些没用的边呢?显然可以,考虑最普通的行矩阵$[1\ 2\ 3\ 4]$。
1指向2就可以了,其实并不需要1指向3,因为2更接近3,当2确定,3才可以确定。
因此,我们可以对$A$的每行每列都排序后,然后按照次序建边。这样,这个图的规模控制在了$O(nm)$。
不仅如此,那么如果存在相同元素,这样就增加了一定的复杂程度。
处理方法,就是将增加一个$eq$邻接表,存储处在同一行或同一列的元素,因为,这些元素的值同时确定。
这样,当进行拓扑时,我们直接从最小值拓扑开始即可(对原始数据排序)。
算法复杂度为$O(nmlog(nm))$。
3.3 代码
/* C */
#include <iostream>
#include <sstream>
#include <string>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <vector>
#include <deque>
#include <bitset>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <ctime>
#include <cstring>
#include <climits>
#include <cctype>
#include <cassert>
#include <functional>
#include <iterator>
#include <iomanip>
using namespace std;
//#pragma comment(linker,"/STACK:102400000,1024000") #define sti set<int>
#define stpii set<pair<int, int> >
#define mpii map<int,int>
#define vi vector<int>
#define pii pair<int,int>
#define vpii vector<pair<int,int> >
#define rep(i, a, n) for (int i=a;i<n;++i)
#define per(i, a, n) for (int i=n-1;i>=a;--i)
#define clr clear
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define all(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define lson l, mid, rt<<1
#define rson mid+1, r, rt<<1|1 const int maxn = 1e6+;
vector<vi> g;
vi E[maxn];
vi eq[maxn];
bool visit[maxn];
int Q[maxn];
int val[maxn];
int ans[maxn];
int n, m; void solve() {
rep(i, , n) {
vpii vp;
rep(j, , m)
vp.pb(mp(g[i][j], j));
sort(all(vp)); rep(j, , m) {
int uid = i*m + vp[j-].sec;
int vid = i*m + vp[j].sec;
if (vp[j].fir == vp[j-].fir) {
eq[uid].pb(vid);
eq[vid].pb(uid);
} else {
E[vid].pb(uid);
}
}
} rep(j, , m) {
vpii vp;
rep(i, , n)
vp.pb(mp(g[i][j], i));
sort(all(vp)); rep(i, , n) {
int uid = vp[i-].sec*m + j;
int vid = vp[i].sec*m + j;
if (vp[i].fir == vp[i-].fir) {
eq[uid].pb(vid);
eq[vid].pb(uid);
} else {
E[vid].pb(uid);
}
}
} int tot = n * m;
int u, v;
vpii vp; rep(i, , tot)
vp.pb(mp(val[i], i)); sort(all(vp)); rep(i, , tot) {
int id = vp[i].sec;
if (visit[id])
continue;
int l = , r = ; Q[r++] = id;
visit[id] = true;
while (l < r) {
u = Q[l++];
int sz = SZ(eq[u]);
rep(j, , sz) {
v = eq[u][j];
if (!visit[v]) {
visit[v] = true;
Q[r++] = v;
}
}
} int mx = ;
rep(j, , r) {
u = Q[j];
int sz = SZ(E[u]);
rep(k, , sz) {
v = E[u][k];
mx = max(mx, ans[v]);
}
} ++mx;
rep(j, , r)
ans[Q[j]] = mx;
} int cnt = ;
rep(i, , n) {
rep(j, , m) {
if (j)
putchar(' ');
printf("%d", ans[cnt++]);
}
putchar('\n');
}
} int main() {
ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
freopen("data.in", "r", stdin);
freopen("data.out", "w", stdout);
#endif int x, cnt = ; scanf("%d%d", &n, &m);
rep(i, , n) {
vi vc;
rep(j, , m) {
scanf("%d", &x);
val[cnt++] = x;
vc.pb(x);
}
g.pb(vc);
} solve(); #ifndef ONLINE_JUDGE
printf("time = %d.\n", (int)clock());
#endif return ;
}
4. Zip-line
4.1 题目描述
$n$棵树,高度分别为$H_i, i \in [1,n]$,m次查询。查询将$H_a$修改为$b$后,最长上升子序列的长度为多少?
4.2 基本思路
这题目就是求$LIS$。思路其实还是挺简单的,初始数组可以求得原始的$LIS$。
因此,修改后的长度至少为$|LIS|-1$,可能达到$|LIS|+1$或者$|LIS|$。
当修改的点不是关键点是,则长度至少为$|LIS|$,否则至少为$|LIS|-1$。
采用离线做,对所有m个查询按照$a$排序,然后使用树状数组或线段树可以计算$LIS$的长度。
$L[i]$表示从1开始以$i$为结尾的上升序列的长度,$R[i]$表示从$n$开始以$i$结尾的下降序列的长度(其实就是从$i$开始以$n$结尾的上升序列)。
$L[i]+R[i]-1$就是经过$i$的上升序列的长度,通过$L[i]+R[i]-1 == |LIS|$以及$cnt$数组的使用可以判定$i$是否为关键点。
$LL[i]$与$RR[i]$的定义了类似,但是针对的是$m$个查询的。因此,$LL[i]+RR[i]-1$就是经过查询修改的点的最长上升子序列的长度,计算过程与上述类似。
二者的最大值,就是修改后整个串的最长上升子序列的长度。
其实这题不难,排序后,就可以均摊了,复杂度为$O(nlgn)$。
4.3 代码
/* D */
#include <iostream>
#include <sstream>
#include <string>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <vector>
#include <deque>
#include <bitset>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <ctime>
#include <cstring>
#include <climits>
#include <cctype>
#include <cassert>
#include <functional>
#include <iterator>
#include <iomanip>
using namespace std;
//#pragma comment(linker,"/STACK:102400000,1024000") #define sti set<int>
#define stpii set<pair<int, int> >
#define mpii map<int,int>
#define vi vector<int>
#define pii pair<int,int>
#define vpii vector<pair<int,int> >
#define rep(i, a, n) for (int i=a;i<n;++i)
#define per(i, a, n) for (int i=n-1;i>=a;--i)
#define clr clear
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define all(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define lson l, mid, rt<<1
#define rson mid+1, r, rt<<1|1 typedef struct node_t {
int a, b, id; friend bool operator< (const node_t& a, const node_t& b) {
return a.a < b.a;
}
} node_t; const int maxn = 8e5+;
const int maxm = 4e5+;
int H[maxm], a[maxn], an = ;
int c[maxn];
int ans[maxm];
node_t Q[maxm];
int L[maxm], R[maxm];
int LL[maxm], RR[maxm];
bool visit[maxn];
int cnt[maxn];
int n, m; inline int lowest(int x) {
return -x & x;
} int main() {
ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
freopen("data.in", "r", stdin);
freopen("data.out", "w", stdout);
#endif scanf("%d%d", &n, &m);
rep(i, , n+) {
scanf("%d", &H[i]);
a[an++] = H[i];
}
rep(i, , m+) {
scanf("%d%d", &Q[i].a, &Q[i].b);
a[an++] = Q[i].b;
Q[i].id = i;
}
sort(a+, a+an);
an = unique(a+, a+an) - (a+);
rep(i, , n+) H[i] = lower_bound(a+, a+an+, H[i]) - a;
rep(i, , m+) Q[i].b = lower_bound(a+, a+an+, Q[i].b) - a; memset(c, , sizeof(c));
rep(i, , n+) {
int mx = ;
for (int j=H[i]-; j; j-=lowest(j))
mx = max(mx, c[j]);
L[i] = ++mx;
for (int j=H[i]; j<=an; j+=lowest(j))
c[j] = max(c[j], mx);
} memset(c, , sizeof(c));
per(i, , n+) {
int mx = ;
for (int j=H[i]+; j<=an; j+=lowest(j))
mx = max(mx, c[j]);
R[i] = ++mx;
for (int j=H[i]; j; j-=lowest(j))
c[j] = max(c[j], mx);
} int lis = ;
rep(i, , n+)
lis = max(lis, R[i]+L[i]-); memset(visit, false, sizeof(visit));
memset(cnt, , sizeof(cnt));
rep(i, , n+) {
if (L[i]+R[i]- == lis) {
visit[i] = true;
++cnt[L[i]];
}
} rep(i, , n+) {
if (visit[i] && cnt[L[i]]>)
visit[i] = false;
} rep(i, , m+) {
if (visit[Q[i].a])
ans[Q[i].id] = lis - ;
else
ans[Q[i].id] = lis;
} sort(Q+, Q++m); memset(c, , sizeof(c));
int j = ;
rep(i, , m+) {
while (j<Q[i].a && j<=n) {
int tmp = L[j];
for (int k=H[j]; k<=an; k+=lowest(k))
c[k] = max(c[k], tmp);
++j;
} int mx = ;
for (int k=Q[i].b-; k; k-=lowest(k))
mx = max(mx, c[k]);
LL[Q[i].id] = ++mx;
} memset(c, , sizeof(c));
j = n;
per(i, , m+) {
while (j>Q[i].a && j) {
int tmp = R[j];
for (int k=H[j]; k; k-=lowest(k))
c[k] = max(c[k], tmp);
--j;
} int mx = ;
for (int k=Q[i].b+; k<=an; k+=lowest(k))
mx = max(mx, c[k]);
RR[Q[i].id] = ++mx;
} rep(i, , m+) {
ans[i] = max(ans[i], LL[i]+RR[i]-);
printf("%d\n", ans[i]);
} #ifndef ONLINE_JUDGE
printf("time = %d.\n", (int)clock());
#endif return ;
}
【Codeforces】#345 Div1的更多相关文章
- 【CodeForces】CodeForcesRound594 Div1 解题报告
点此进入比赛 \(A\):Ivan the Fool and the Probability Theory(点此看题面) 大致题意: 给一个\(n\times m\)的矩阵\(01\)染色,使得不存在 ...
- 【CodeForces】CodeForcesRound576 Div1 解题报告
点此进入比赛 \(A\):MP3(点此看题面) 大致题意: 让你选择一个值域区间\([L,R]\),使得序列中满足\(L\le a_i\le R\)的数的种类数不超过\(2^{\lfloor\frac ...
- 【Codeforces】Round #491 (Div. 2) 总结
[Codeforces]Round #491 (Div. 2) 总结 这次尴尬了,D题fst,E没有做出来.... 不过还好,rating只掉了30,总体来说比较不稳,下次加油 A:If at fir ...
- 【Codeforces】Round #488 (Div. 2) 总结
[Codeforces]Round #488 (Div. 2) 总结 比较僵硬的一场,还是手速不够,但是作为正式成为竞赛生的第一场比赛还是比较圆满的,起码没有FST,A掉ABCD,总排82,怒涨rat ...
- 【CodeForces】601 D. Acyclic Organic Compounds
[题目]D. Acyclic Organic Compounds [题意]给定一棵带点权树,每个点有一个字符,定义一个结点的字符串数为往下延伸能得到的不重复字符串数,求min(点权+字符串数),n&l ...
- 【Codeforces】849D. Rooter's Song
[算法]模拟 [题意]http://codeforces.com/contest/849/problem/D 给定n个点从x轴或y轴的位置p时间t出发,相遇后按对方路径走,问每个数字撞到墙的位置.(还 ...
- 【CodeForces】983 E. NN country 树上倍增+二维数点
[题目]E. NN country [题意]给定n个点的树和m条链,q次询问一条链(a,b)最少被多少条给定的链覆盖.\(n,m,q \leq 2*10^5\). [算法]树上倍增+二维数点(树状数组 ...
- 【CodeForces】925 C.Big Secret 异或
[题目]C.Big Secret [题意]给定数组b,求重排列b数组使其前缀异或和数组a单调递增.\(n \leq 10^5,1 \leq b_i \leq 2^{60}\). [算法]异或 为了拆位 ...
- 【CodeForces】700 D. Huffman Coding on Segment 哈夫曼树+莫队+分块
[题目]D. Huffman Coding on Segment [题意]给定n个数字,m次询问区间[l,r]的数字的哈夫曼编码总长.1<=n,m,ai<=10^5. [算法]哈夫曼树+莫 ...
随机推荐
- ASP.NET 发送电子邮件简介
1.补充知识 (1)POP3和SMTP服务器是什么? 简单点来说:POP3 用于接收电子邮件 ,SMTP 用于发送电子邮件. (1)POP3具体指什么? POP3(Post Office Protoc ...
- js-shortid:优雅简洁地实现短ID
短ID在实际运用中很广泛, 其中比较典型的运用就是短地址. 市面上肯定有不少开源的生成短ID库, 基于node.js的估计也不少. 鉴于本人已然是node.js的脑残粉(本职java开发), 很多业余 ...
- Div 内部所有元素 全部垂直对齐
http://stackoverflow.com/questions/7273338/how-to-vertically-align-an-image-inside-div How it works: ...
- 在Linux上部署和操作Couchbase
couchbase属于nosql系列,个人感觉它要比mongodb操作简单,mongo的查询语句太复杂.在数据的持久性方面它区别于其他nosql 的唯一大亮点是不受限于其内存分配了多少,只要磁盘空间够 ...
- eclipse 分屏
刚刚一直找不到eclipse分屏功能,查了下发现是可以的. 具体见:http://www.coderanch.com/t/101996/vc/Split-screen-editor-Eclipse E ...
- LAMP(Ubuntu+apache+mysql+php)+Zend Studio 新手の PHP的开发环境搭建
因为工作需要,就从c#转型过来研究PHP.可是没想到从一开始就遇上了问题,环境配置方面的问题足足令我头疼了两天.因为博主本人对于linux的接触非常少,所以在解决这个问题的时候也学到了不少东西, 非常 ...
- Delphi中的四舍五入函数
一.Delphi中的四舍五入法 四舍五入是一种应用非常广泛的近似计算方法,针对不同的应用需求,其有算术舍入法和银行家舍入法两种. 所谓算术舍入法,就是我们通常意义上的四舍五入法.其规则 ...
- html lang
目前,语言的标签表示法的国际标准是RFC 4646,名称是<Tags for Identifying Languages>.简单说,这个文件规定,一种语言的标签应该按照如下方式排列: la ...
- 模式对话框里的CheckedChanged事件
问题: 模式对话框里的CheckedChanged事件不被触发: 解决方法: 一.先不直接showModalDialog出要的页面,而是要放一个中单页面 window.showModalDialo ...
- 动态设置uitableview高度,参考
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { // ...