C++100分代码通过,真的太不容易了
题面
链接:https://www.nowcoder.com/questionTerminal/96bf0c548a094de7a05919e0b32b1a5a
来源:牛客网
小汪作为一个有数学天分的程序猿,设计了一套密码生成器来搞定自己的密码问题。
密码生成器由N个槽位组成,槽位的下标为0~N-1,每个槽位存储一个数。起初每个槽位都是0。
密码生成器会进行M轮计算,每轮计算,小汪会输入两个数L,R(L<=R),密码生成器会将这两个数作为下标,将两个下标之间(包含)的所有槽位赋值为i(i为当前的轮次,i∈[1,M])。
M轮计算完成后,密码生成器会根据槽位的最终值生成一条密码,密码的生成规则为:
(0*a[0] + 1*a[1] + 2*a[2] + ... + (N-1)*a[N-1]) mod 100000009
其中a[i]表示第i个槽位的最终值。
请帮助小汪把他的密码生成器实现为代码。
输入描述:
第一行为两个整数N,M,表示槽位个数和计算轮数。
接下来M行,每行两个整数Li,Ri,表示第i轮计算的输入。
输出描述:
输出一行,一个整数A,表示小汪的开机密码。
示例1
输入
5 3 2 3 1 2 1 1
输出
10
说明
对于输入样例,密码生成过程如下:
初始: 0 0 0 0 0 第1轮:0 0 1 1 0 第2轮:0 2 2 1 0 第3轮:0 3 2 1 0
密码生成器最终生成 0 3 2 1 0,则密码为(0*0 + 3*1 + 2*2 + 1*3 + 0*4) mod 100000009 = 10
备注:
mod 表示取余操作,a mod b表示a,b相除得到的余数
对于前30%的测试数据,保证 N,M<=10000
对于前50%的测试数据,保证 N,M<=200000
对于100%的测试数据,保证 N<=1.5*10^7,M<=200000
思路
那么本题的正解是采用离散化+线段树
首先区间赋值很容易想到的是线段树,而纯线段树会爆空间,只能拿到50分,如果写动态开点线段树没准会过,先上一个50分代码...
50分代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#define Lchild(x) ((x) << 1)
#define Rchild(x) (((x) << 1) + 1)
using namespace std;
typedef long long ll;
const ll MOD = 100000009;
const int maxn = 15000010;
inline void write(ll x) {
if (x < 0)putchar('-'), x = -x;
if (x > 9)write(x / 10);
putchar(x % 10 + 48);
}
inline int read() {
int k = 0, f = 1;
char c = getchar();
while (c < '0' || c>'9') {
if (c == '-')f = -1;
c = getchar();
}
while (c >= '0' && c <= '9') {
k = (k << 1) + (k << 3) + c - 48;
c = getchar();
}
return k * f;
}
struct op {
int l, r, c;
}a[maxn];
//[l, r]的区间和
inline ll sum(ll l, ll r) { return (l + r) * (r - l + 1) / 2; }
int n, m;
int x[maxn << 1], x_size, realx_size, c[maxn << 1];
int L, R;
ll ans;
struct SegmentTree {
struct Node {
int value, tag_Set;
}nodes[maxn << 2];
SegmentTree() {
memset(nodes, 0, sizeof(nodes));
}
inline void pushup(int root) {
nodes[root].value = nodes[Lchild(root)].value + nodes[Rchild(root)].value;
}
inline void build(int root, int l, int r) {
nodes[root].tag_Set = 0;
if (l == r)nodes[root].value = 0;
else {
int m = (l + r) >> 1;
build(Lchild(root), l, m);
build(Rchild(root), m + 1, r);
pushup(root);
}
}
inline void pushdown(int root, int l, int r) {
int m = (l + r) >> 1;
if (nodes[root].tag_Set) {
nodes[Lchild(root)].tag_Set = nodes[Rchild(root)].tag_Set = nodes[root].tag_Set;
nodes[Lchild(root)].value = (m - l + 1) * nodes[root].tag_Set;
nodes[Rchild(root)].value = (r - m) * nodes[root].tag_Set;
nodes[root].tag_Set = 0;
}
}
inline void updateSet(int root, int curl, int curr, int tarl, int tarr, int k) {
if (tarr < curl || curr < tarl)return;
if (tarl <= curl && curr <= tarr) {
nodes[root].tag_Set = k;
nodes[root].value = (curr - curl + 1) * k;
return;
}
pushdown(root, curl, curr);
int m = (curl + curr) >> 1;
if (tarl <= m) updateSet(Lchild(root), curl, m, tarl, tarr, k);
if (tarr > m) updateSet(Rchild(root), m + 1, curr, tarl, tarr, k);
pushup(root);
}
inline int query(int root, int curl, int curr, int tarl, int tarr) {
if (tarr < curl || curr < tarl)return 0;
if (tarl <= curl && curr <= tarr) {
return nodes[root].value;
}
pushdown(root, curl, curr);
int m = (curl + curr) >> 1;
int ret = 0;
if (tarl <= m) ret += query(Lchild(root), curl, m, tarl, tarr);
if (tarr > m) ret += query(Rchild(root), m + 1, curr, tarl, tarr);
return ret;
}
};
SegmentTree tree;
int main() {
n = read(), m = read();
tree.build(1, 1, n);
for (int i = 1; i <= m; ++i) {
L = read() + 1, R = read() + 1;
tree.updateSet(1, 1, n, L, R, i);
}
for (int i = 0; i < n; ++i)
ans = (ans + 1ll * tree.query(1, 1, n, i + 1, i + 1) * i) % MOD;
write(ans);
} 那么考虑到数据范围,我们需要对区间进行离散化,把所有的端点坐标罗列下来,排序去重
比如说一共4个坐标点
1 4 6 10000000000
我们就可以映射到
1 2 3 4
然后接下来,只需要在赋值的时候直接在离散化的点上操作就可以
但是这样只能拿到20分,还有一个小问题
就是当我们的赋值是在1到4和6到10000000000的时候,就会忽略掉5会怎么样
所以当相邻两个点x和y的差大于1的时候,我们需要将x+1和y-1同时加入离散化的坐标数组,再做一次排序去重
100分代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#define Lchild(x) ((x) << 1)
#define Rchild(x) (((x) << 1) + 1)
using namespace std;
typedef long long ll;
const ll MOD = 100000009;
const int maxn = 1000010;
inline void write(ll x) {
if (x < 0)putchar('-'), x = -x;
if (x > 9)write(x / 10);
putchar(x % 10 + 48);
}
inline int read() {
int k = 0, f = 1;
char c = getchar();
while (c < '0' || c>'9') {
if (c == '-')f = -1;
c = getchar();
}
while (c >= '0' && c <= '9') {
k = (k << 1) + (k << 3) + c - 48;
c = getchar();
}
return k * f;
}
struct op {
int l, r;
}a[maxn];
//[l, r]的区间和
inline ll sum(ll l, ll r) {return (l + r) * (r - l + 1) / 2;}
int n, m;
int x[maxn << 1], x_size, realx_size, c[maxn << 1];
int L, R;
ll ans;
struct SegmentTree {
struct Node {
int value, tag_Set;
}nodes[maxn << 3];
SegmentTree() {
memset(nodes, 0, sizeof(nodes));
}
inline void pushup(int root) {
nodes[root].value = nodes[Lchild(root)].value + nodes[Rchild(root)].value;
}
inline void build(int root, int l, int r) {
nodes[root].tag_Set = 0;
if (l == r)nodes[root].value = 0;
else {
int m = (l + r) >> 1;
build(Lchild(root), l, m);
build(Rchild(root), m + 1, r);
pushup(root);
}
}
inline void pushdown(int root, int l, int r) {
int m = (l + r) >> 1;
if(nodes[root].tag_Set) {
nodes[Lchild(root)].tag_Set = nodes[Rchild(root)].tag_Set = nodes[root].tag_Set;
nodes[Lchild(root)].value = (m - l + 1) * nodes[root].tag_Set;
nodes[Rchild(root)].value = (r - m) * nodes[root].tag_Set;
nodes[root].tag_Set = 0;
}
}
inline void updateSet(int root, int curl, int curr, int tarl, int tarr, int k) {
if (tarr < curl || curr < tarl)return;
if (tarl <= curl && curr <= tarr) {
nodes[root].tag_Set = k;
nodes[root].value = (curr - curl + 1) * k;
return;
}
pushdown(root, curl, curr);
int m = (curl + curr) >> 1;
if (tarl <= m) updateSet(Lchild(root), curl, m, tarl, tarr, k);
if (tarr > m) updateSet(Rchild(root), m + 1, curr, tarl, tarr, k);
pushup(root);
}
inline int query(int root, int curl, int curr, int tarl, int tarr) {
if (tarr < curl || curr < tarl)return 0;
if (tarl <= curl && curr <= tarr) {
return nodes[root].value;
}
pushdown(root, curl, curr);
int m = (curl + curr) >> 1;
int ret = 0;
if (tarl <= m) ret += query(Lchild(root), curl, m, tarl, tarr);
if (tarr > m) ret += query(Rchild(root), m + 1, curr, tarl, tarr);
return ret;
}
};
SegmentTree tree;
int main() {
n = read(), m = read();
for(int i = 1; i <= m; ++i) {
x[++x_size] = a[i].l = read();
x[++x_size] = a[i].r = read();
}
sort(x + 1, x + x_size + 1);
realx_size = unique(x + 1, x + x_size + 1) - x - 1;
x_size = realx_size;
for(int i = 2; i <= x_size; ++i)
if(x[i] - x[i - 1] > 1) x[++realx_size] = x[i] - 1, x[++realx_size] = x[i - 1] + 1;
x_size = realx_size;
sort(x + 1, x + x_size + 1);
realx_size = unique(x + 1, x + x_size + 1) - x - 1;
tree.build(1, 1, realx_size);
for(int i = 1; i <= m; ++i) {
L = lower_bound(x + 1, x + realx_size + 1, a[i].l) - x;
R = lower_bound(x + 1, x + realx_size + 1, a[i].r) - x;
tree.updateSet(1, 1, realx_size, L, R, i);
}
for(int i = 1; i <= realx_size; ++i)
c[i] = tree.query(1, 1, realx_size, i, i);
for(int i = 1; i < realx_size; ++i)
ans = (ans + sum(x[i], x[i + 1] - 1) * (1ll * c[i])) % MOD;
ans = (ans + x[realx_size] * (1ll * c[realx_size])) % MOD;
write(ans);
} 
京公网安备 11010502036488号