第十四次CCF-CSP
第二题 买菜
原题链接:3263. 买菜 - AcWing题库
思路分析
简单来说,就是给出两组区间的集合A,B 求出两集合中相交区间的部分的长度,注意若区间 [s,t] 是相交的,则长度为 t-s 。
思路一
因为数据量比较小,n<2e3. 所以可以直接暴力:
代码如下
#include<bits/stdc++.h>
using namespace std;
const int N = 2020;
int n;
int a[N], b[N], c[N], d[N];
bool f[N];
int ans;
int main()
{
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> a[i] >> b[i];
}
for (int i = 1; i <= n; i++)
{
cin >> c[i] >> d[i];
}
for ( int i=1;i <= n; i++)
{
for(int j = 1;j<=n;j++)
{
int x=0,y=0;
if(c[j]>b[i] || d[j]< a[i])
continue;
x = max(a[i],c[j]);
y = min(b[i],d[j]);
ans += y-x;
}
}
cout << ans;
return 0;
}
思路二
因为所有的区间值都在1e6之内。所以我们可以把区间内的所有值(半闭半开区间!)映射到一条长的线段上去。当出现了区间内的值,就 + 1,所以我们只需要在该线段上找到值为 2 的个数即可。
为什么要半闭半开?
因为题目要求 [s,t] 的长度为 t - s。并不是 t - s + 1。所以我们只需要在预处理的时候,少映射一位数即可。
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+5;
int n;
int a[N];
long long ans;
int main()
{
cin >> n;
int x, y,m;
for (int i = 1; i <= n; i++)
{
cin >> x >> y;
m = max(m, y);
for (int j = x; j < y; j++)
a[j] += 1;
}
for (int i = 1; i <= n; i++)
{
cin >> x >> y;
m = max(m, y);
for (int j = x; j < y; j++)
{
a[j] += 1;
}
}
for (int i = 1; i <= m; i++)
{
int j = i+1;
while (a[j] == 2 && j <= m)
{
j++;
}
ans += j - i - 1;
i = j - 1;
}
cout << ans;
return 0;
}
第四题 再卖菜
原题链接:3265. 再卖菜 - AcWing题库
思路分析
这道题运用了差分约束的思想,差分的结论如下:
- 要找最大值,就等价于找最短路 a + c >= b, add(a,b,c) 即有一条从a指向b的权重为c的有向边
- 要找最小值,就等价于找最长路 a + c <= b, add(a,b,c)
在本题中的具体推导过程见下图:
所以,我们可以建图如下:
for (int i = 2; i < n; i++)
{
add(i - 2, i + 1, 3 * b[i]);
add(i + 1, i - 2, -(3 * b[i] + 2));
}
add(0, 2, 2 * b[1]); add(2, 0, -(2 * b[1] + 1));
add(n - 2, n, 2 * b[n]); add(n, n - 2, -(2 * b[n] + 1));
for (int i = 1; i <= n; i++)
{
add(i - 1, i, 1);
}
建好图之后,只需要用SPFA算法跑一遍(因为有负数),求最长路即可。
void spfa() //基本上就是套模板
{
memset(dist, -0x3f, sizeof dist);
dist[0] = 0;
q.push(0);
while (!q.empty())
{
int t = q.front();
q.pop();
st[t] = false; //注意这里的标记数组
for (int i = h[t]; ~i; i = ne[i])
{
int j = e[i];
if (dist[j] < dist[t] + w[i])
{
dist[j] = dist[t] + w[i];
st[t] = true;
}
}
}
}
整体代码
#include<bits/stdc++.h>
using namespace std;
const int N = 310, M = 3 * N;
int n;
int b[N];
int h[N], e[M], ne[M], w[M], idx;
int dist[N];
queue<int> q;
bool st[N];
void add(int a, int b, int c)
{
e[idx] = b; w[idx] = c; ne[idx] = h[a]; h[a] = idx++;
}
void spfa()
{
memset(dist, -0x3f, sizeof dist);
dist[0] = 0;
q.push(0);
while (!q.empty())
{
int t = q.front();
q.pop();
st[t] = false;
for (int i = h[t]; ~i; i = ne[i])
{
int j = e[i];
if (dist[j] < dist[t] + w[i])
{
dist[j] = dist[t] + w[i];
st[t] = true;
}
}
}
}
int main()
{
cin >> n;
memset(h, -1, sizeof h);
for (int i = 1; i <= n; i++)
cin >> b[i];
for (int i = 2; i < n; i++)
{
add(i - 2, i + 1, 3 * b[i]);
add(i + 1, i - 2, -(3 * b[i] + 2));
}
add(0, 2, 2 * b[1]); add(2, 0, -(2 * b[1] + 1));
add(n - 2, n, 2 * b[n]); add(n, n - 2, -(2 * b[n] + 1));
for (int i = 1; i <= n; i++)
{
add(i - 1, i, 1);
}
spfa();
for (int i = 1; i <= n; i++)
{
cout << dist[i] - dist[i - 1] << " ";
}
return 0;
}