洛谷-算法2-1-前缀和、差分与离散化2

P1955 [NOI2015] 程序自动分析

题目描述

在实现程序自动分析的过程中,常常需要判定一些约束条件是否能被同时满足。

考虑一个约束满足问题的简化版本:假设 x1​,x2​,x3​,⋯ 代表程序中出现的变量,给定 n 个形如 xi​=xj​ 或 xi​=xj​ 的变量相等/不等的约束条件,请判定是否可以分别为每一个变量赋予恰当的值,使得上述所有约束条件同时被满足。例如,一个问题中的约束条件为:x1​=x2​,x2​=x3​,x3​=x4​,x4​=x1​,这些约束条件显然是不可能同时被满足的,因此这个问题应判定为不可被满足。

现在给出一些约束满足问题,请分别对它们进行判定。

输入格式

输入的第一行包含一个正整数 t,表示需要判定的问题个数。注意这些问题之间是相互独立的。

对于每个问题,包含若干行:

第一行包含一个正整数 n,表示该问题中需要被满足的约束条件个数。接下来 n 行,每行包括三个整数 i,j,e,描述一个相等/不等的约束条件,相邻整数之间用单个空格隔开。若 e=1,则该约束条件为 xi​=xj​。若 e=0,则该约束条件为 xi​=xj​。

输出格式

输出包括 t 行。

输出文件的第 k 行输出一个字符串 YES 或者 NO(字母全部大写),YES 表示输入中的第 k 个问题判定为可以被满足,NO 表示不可被满足。

输入输出样例

输入 #1复制

复制代码
2
2
1 2 1
1 2 0
2
1 2 1
2 1 1

输出 #1复制

复制代码
NO
YES

输入 #2复制

复制代码
2
3
1 2 1
2 3 1
3 1 1
4
1 2 1
2 3 1
3 4 1
1 4 0

输出 #2复制

复制代码
YES
NO

说明/提示

【样例解释 1】

在第一个问题中,约束条件为:x1​=x2​,x1​=x2​。这两个约束条件互相矛盾,因此不可被同时满足。

在第二个问题中,约束条件为:x1​=x2​,x1​=x2​。这两个约束条件是等价的,可以被同时满足。

【样例说明 2】

在第一个问题中,约束条件有三个:x1​=x2​,x2​=x3​,x3​=x1​。只需赋值使得 x1​=x2​=x3​,即可同时满足所有的约束条件。

在第二个问题中,约束条件有四个:x1​=x2​,x2​=x3​,x3​=x4​,x4​=x1​。由前三个约束条件可以推出 x1​=x2​=x3​=x4​,然而最后一个约束条件却要求 x1​=x4​,因此不可被满足。

【数据范围】

所有测试数据的范围和特点如下表所示:

测试点编号 n 的规模 i,j 的规模 约定
1 1≤n≤10 1≤i,j≤104 1≤t≤10e∈{0,1}
2 1≤n≤10 1≤i,j≤104 1≤t≤10e∈{0,1}
3 1≤n≤100 1≤i,j≤104 1≤t≤10e∈{0,1}
4 1≤n≤100 1≤i,j≤104 1≤t≤10e∈{0,1}
5 1≤n≤105 1≤i,j≤104 1≤t≤10e∈{0,1}
6 1≤n≤105 1≤i,j≤104 1≤t≤10e∈{0,1}
7 1≤n≤105 1≤i,j≤104 1≤t≤10e∈{0,1}
8 1≤n≤105 1≤i,j≤109 1≤t≤10e∈{0,1}
9 1≤n≤105 1≤i,j≤109 1≤t≤10e∈{0,1}
10 1≤n≤105 1≤i,j≤109 1≤t≤10e∈{0,1}

实现代码:

cpp 复制代码
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <cstdlib>
using namespace std;
int t,n,f[1000007],book[1000007*3]; 
struct node{
    int x,y,e;
}a[1000001];  
bool cmp(node a,node b){
    return a.e>b.e;
}
inline void first(int kkk){
    for(int i=1;i<=kkk;i++)  f[i]=i;
}
int get(int x){
    if(x==f[x]) return x;
    return f[x]=get(f[x]);
}
int main(){
    scanf("%d",&t);
    while(t--){
      int tot=-1;
      memset(book,0,sizeof(book));
      memset(a,0,sizeof(a));
      memset(f,0,sizeof(f));
    int flag=1;
        scanf("%d",&n);
       
        for(int i=1;i<=n;i++){
            scanf("%d %d %d",&a[i].x,&a[i].y,&a[i].e);
            book[++tot]=a[i].x;
            book[++tot]=a[i].y;
        }
        sort(book,book+tot);
        int reu=unique(book,book+tot)-book;
        for(int i=1;i<=n;++i){
           a[i].x=lower_bound(book,book+reu,a[i].x)-book;
           a[i].y=lower_bound(book,book+reu,a[i].y)-book;   
        } 
        first(reu); 
        sort(a+1,a+n+1,cmp);
        for(int i=1;i<=n;i++){
            int r1=get(a[i].x);
            int r2=get(a[i].y);
            if(a[i].e){
                f[r1]=r2; 
            }else if(r1==r2){
                printf("NO\n");
                flag=0; 
                break;
            }
        }
        if(flag)    printf("YES\n"); 
    }
    return 0;
}

P1884 [USACO12FEB] Overplanting S

题目描述

在一个笛卡尔平面坐标系里(则 X 轴向右是正方向,Y 轴向上是正方向),有 N (1≤N≤1000) 个矩形,第 i 个矩形的左上角坐标是 (x1​,y1​),右下角坐标是 (x2​,y2​)。问这 N 个矩形所覆盖的面积是多少?

注意:被重复覆盖的区域的面积只算一次。

输入格式

第一行,一个整数 N (1≤N≤1000)。

接下来有 N 行,每行描述一个矩形的信息,分别是矩形的 x1​,y1​,x2​,y2​(−108≤x1​,y1​,x2​,y2​≤108)。

输出格式

一个整数,被 N 个矩形覆盖的区域的面积。

输入输出样例

输入 #1复制

复制代码
2
0 5 4 1
2 4 6 2

输出 #1复制

复制代码
20

实现代码:

cpp 复制代码
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#define maxn 1010
using namespace std;

long long n,x[maxn],y[maxn],x2[maxn],y2[maxn],side[2*maxn];
int arr[maxn];
long long ans;

bool cmp(int a,int b)
{
	return y[a]>y[b];
}

int main()
{
	cin >> n;
	for (int i=0;i<n;i++) 
	{
		cin >> x[i] >> y[i] >> x2[i] >> y2[i];
		side[2*i]=x[i];
		side[2*i+1]=x2[i];
	}
	sort(side,side+2*n);
	ans=0;
	for (int i=1;i<2*n;i++)
	{
		if (side[i-1]==side[i]) continue;
		int m=0;
		for (int j=0;j<n;j++)
		{
			if (x[j]<=side[i-1] && side[i]<=x2[j]) arr[m++]=j;
		}
		sort(arr,arr+m,cmp);
		long long h=y[arr[0]],d=y2[arr[0]],w=side[i]-side[i-1];
		for (int j=1;j<m;j++)
		{
			int temp=arr[j];
			if (y[temp]>d)
			{
				ans+=(h-y[temp])*w;
				h=y[temp];
			}
			else
			{
				ans+=(h-d)*w;
				h=y[temp];
			}
			if (y2[temp]<d) d=y2[temp];
		}
		ans+=(h-d)*w;
	}
	cout << ans << endl;
}

P2004 领地选择

题目描述

作为在虚拟世界里统帅千军万马的领袖,小 Z 认为天时、地利、人和三者是缺一不可的,所以,谨慎地选择首都的位置对于小 Z 来说是非常重要的。

首都被认为是一个占地 C×C 的正方形。小 Z 希望你寻找到一个合适的位置,使得首都所占领的位置的土地价值和最高。

输入格式

第一行三个整数 N,M,C,表示地图的宽和长以及首都的边长。

接下来 N 行每行 M 个整数,表示了地图上每个地块的价值。价值可能为负数。

输出格式

一行两个整数 X,Y,表示首都左上角的坐标。保证最优解是唯一的。

输入输出样例

输入 #1复制

复制代码
3 4 2
1 2 3 1
-1 9 0 2
2 0 1 1

输出 #1复制

复制代码
1 2

说明/提示

对于 60% 的数据,N,M≤50。

对于 90% 的数据,N,M≤300。

对于 100% 的数据,1≤N,M≤103,1≤C≤min(N,M),每块地价值的绝对值不超过 32767。

实现代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int n,m,c;
const int N=1e3+10;
int a[N][N],hang[N][N];
long long sum[N][N];

int main(){
	cin>>n>>m>>c;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>a[i][j];
			hang[i][j]=a[i][j]+hang[i][j-1];
			sum[i][j]=hang[i][j]+sum[i-1][j];
		}
	}
	long long X,Y,maxn=0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if((i+c-1>n)||(j+c-1>m)) continue;
			long long k=sum[i+c-1][j+c-1]+sum[i-1][j-1]-sum[i-1][j+c-1]-sum[i+c-1][j-1];
			if(k>maxn){
				maxn=k;
				X=i;
				Y=j;
			}
		}
	}
	cout<<X<<" "<<Y;
	return 0;
}

P3017 [USACO11MAR] Brownie Slicing G

题目描述

Bessie 烤了一个长方形的布朗尼,可以看作是一个 R×C 的网格(1≤R≤500;1≤C≤500),由小方块组成。在第 i 行,第 j 列的方块中有 Nij​(0≤Nij​≤4,000)颗巧克力豆。

Bessie 想把布朗尼分成 A×B 块(1≤A≤R;1≤B≤C):每头牛一块。布朗尼的切割方式是先进行 A−1 次水平切割(总是在整数坐标上),将布朗尼分成 A 条带。然后每条带独立地进行 B−1 次垂直切割,也是在整数边界上。其他 A×B−1 头牛各自选择一块布朗尼,剩下最后一块给 Bessie。由于它们很贪心,它们会把巧克力豆最少的一块留给 Bessie。

假设 Bessie 以最优方式切割布朗尼,求 Bessie 能获得的最多巧克力豆数。

例如,考虑一个 5 行 4 列的布朗尼,巧克力豆分布如下:

复制代码
1 2 2 1
3 1 1 1
2 0 1 3
1 1 1 1
1 1 1 1

Bessie 必须将布朗尼分成 4 条水平带,每条带有两块。Bessie 可以这样切割布朗尼:

复制代码
1 2 | 2 1
---------
3 | 1 1 1
---------
2 0 1 | 3
---------
1 1 | 1 1
1 1 | 1 1

因此,当其他贪心的牛选择它们的布朗尼块时,Bessie 仍然可以得到 3 颗巧克力豆。

输入格式

* 第 1 行:四个用空格分隔的整数:R,C,A 和 B

* 第 2 行到第 R+1 行:第 i+1 行包含 C 个用空格分隔的整数:Ni1​,...,NiC​

输出格式

* 第 1 行:一个整数:Bessie 在她的布朗尼上能保证获得的最多巧克力豆数

显示翻译

题意翻译

输入输出样例

输入 #1复制

复制代码
5 4 4 2 
1 2 2 1 
3 1 1 1 
2 0 1 3 
1 1 1 1 
1 1 1 1 

输出 #1复制

复制代码
3 

说明/提示

(由 ChatGPT 4o 翻译)

实现代码:

cpp 复制代码
#include<iostream>
#include<cstdio>
using namespace std;
int r,c,a,b,map[501][501],s[501][501],ans;
bool check(int x)
{
    int now=0,num=0;
    for (int i=1;i<=r;i++)
    {
        int dis=0,sum=0;
        for (int j=1;j<=c;j++)
            if (dis+(s[i][j]-s[i][j-1])-(s[now][j]-s[now][j-1])<x)
                dis+=(s[i][j]-s[i][j-1])-(s[now][j]-s[now][j-1]);
            else
            {
                sum++;
                dis=0;
            }
        if (sum>=b)
        {
            now=i;num++;
        }
    }
    if (num<a) return 0;
    return 1; 
}
int main()
{
    cin>>r>>c>>a>>b;
    for (int i=1;i<=r;i++)
        for (int j=1;j<=c;j++)
            cin>>map[i][j];
    for (int i=1;i<=r;i++)
        for (int j=1;j<=c;j++)
            s[i][j]=s[i-1][j]+s[i][j-1]+map[i][j]-s[i-1][j-1];
    int h=0,t=s[r][c];
    while (h<=t)
    {
        int mid=(h+t)/2;
        if (check(mid))
        {
            h=mid+1;
            ans=mid;
        }
        else t=mid-1;
    }
    cout<<ans;
}

P3406 海底高铁

题目描述

该铁路经过 N 个城市,每个城市都有一个站。不过,由于各个城市之间不能协调好,于是乘车每经过两个相邻的城市之间(方向不限),必须单独购买这一小段的车票。第 i 段铁路连接了城市 i 和城市 i+1(1≤i<N)。如果搭乘的比较远,需要购买多张车票。第 i 段铁路购买纸质单程票需要 Ai​ 博艾元。

虽然一些事情没有协调好,各段铁路公司也为了方便乘客,推出了 IC 卡。对于第 i 段铁路,需要花 Ci​ 博艾元的工本费购买一张 IC 卡,然后乘坐这段铁路一次就只要扣 Bi​(Bi​<Ai​) 元。IC 卡可以提前购买,有钱就可以从网上买得到,而不需要亲自去对应的城市购买。工本费不能退,也不能购买车票。每张卡都可以充值任意数额。对于第 i 段铁路的 IC 卡,无法乘坐别的铁路的车。

Uim 现在需要出差,要去 M 个城市,从城市 P1​ 出发分别按照 P1​,P2​,P3​,⋯,PM​ 的顺序访问各个城市,可能会多次访问一个城市,且相邻访问的城市位置不一定相邻,而且不会是同一个城市。

现在他希望知道,出差结束后,至少会花掉多少的钱,包括购买纸质车票、买卡和充值的总费用。

输入格式

第一行两个整数,N,M。

接下来一行,M 个数字,表示 Pi​。

接下来 N−1 行,表示第 i 段铁路的 Ai​,Bi​,Ci​。

输出格式

一个整数,表示最少花费。

输入输出样例

输入 #1复制

复制代码
9 10
3 1 4 1 5 9 2 6 5 3
200 100 50
300 299 100
500 200 500
345 234 123
100 50 100
600 100 1
450 400 80
2 1 10

输出 #1复制

复制代码
6394

说明/提示

2 到 3 以及 8 到 9 买票,其余买卡。

对于 30% 数据 M=2。

对于另外 30% 数据 N≤1000,M≤1000。

对于 100% 的数据 M,N≤105,Ai​,Bi​,Ci​≤105。

实现代码:

cpp 复制代码
#include<iostream>
using namespace std;
char ch;
template<class T>
inline void rd(T& x) {
    x = 0; int w = 1;
    ch = getchar();
    while (ch < '0' || ch>'9') {
        if (ch == '-')w = -1; ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = (x << 1) + (x << 3) + ch - '0';
        ch = getchar();
    }
    x = x * w;
}
int a[100001];  unsigned long long t ,sum;
int main()
{
    int n, m,x,y,z;
    rd(n), rd(m);
    rd(x);
    for (int i = 2; i <= m; i++)
    {
        rd(y);
        if (x < y) 
        {
            a[x]++;
            a[y]--;
        }
        else
        {
            a[x]--;
            a[y]++;
        }
        x = y;
    }
  
    for (int i = 1; i < n; i++)
    {
        t += a[i];
        rd(x),rd(y),rd(z);
        sum += t * y + z < t * x ? t * y + z : t * x; 
        
    }
    cout << sum;
    return 0;
}

P1083 [NOIP 2012 提高组] 借教室

题目描述

在大学期间,经常需要租借教室。大到院系举办活动,小到学习小组自习讨论,都需要向学校申请借教室。教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样。

面对海量租借教室的信息,我们自然希望编程解决这个问题。

我们需要处理接下来 n 天的借教室信息,其中第 i 天学校有 ri​ 个教室可供租借。共有 m 份订单,每份订单用三个正整数描述,分别为 dj​,sj​,tj​,表示某租借者需要从第 sj​ 天到第 tj​ 天租借教室(包括第 sj​ 天和第 tj​ 天),每天需要租借 dj​ 个教室。

我们假定,租借者对教室的大小、地点没有要求。即对于每份订单,我们只需要每天提供 dj​ 个教室,而它们具体是哪些教室,每天是否是相同的教室则不用考虑。

借教室的原则是先到先得,也就是说我们要按照订单的先后顺序依次为每份订单分配教室。如果在分配的过程中遇到一份订单无法完全满足,则需要停止教室的分配,通知当前申请人修改订单。这里的无法满足指从第 sj​ 天到第 tj​ 天中有至少一天剩余的教室数量不足 dj​ 个。

现在我们需要知道,是否会有订单无法完全满足。如果有,需要通知哪一个申请人修改订单。

输入格式

第一行包含两个正整数 n,m,表示天数和订单的数量。

第二行包含 n 个正整数,其中第 i 个数为 ri​,表示第 i 天可用于租借的教室数量。

接下来有 m 行,每行包含三个正整数 dj​,sj​,tj​,表示租借的数量,租借开始、结束分别在第几天。

每行相邻的两个数之间均用一个空格隔开。天数与订单均用从 1 开始的整数编号。

输出格式

如果所有订单均可满足,则输出只有一行,包含一个整数 0。

否则(订单无法完全满足)输出两行,第一行输出一个负整数 −1,第二行输出需要修改订单的申请人编号。

输入输出样例

输入 #1复制

复制代码
4 3 
2 5 4 3 
2 1 3 
3 2 4 
4 2 4

输出 #1复制

复制代码
-1 
2

说明/提示

【输入输出样例说明】

第 1 份订单满足后,4 天剩余的教室数分别为 0,3,2,3。第 2 份订单要求第 2 天到第 4 天每天提供 3 个教室,而第 3 天剩余的教室数为 2,因此无法满足。分配停止,通知第 2 个申请人修改订单。

【数据范围】

对于 10% 的数据,有 1≤n,m≤10;

对于 30% 的数据,有 1≤n,m≤1000;

对于 70% 的数据,有 1≤n,m≤105;

对于 100% 的数据,有 1≤n,m≤106,0≤ri​,dj​≤109,1≤sj​≤tj​≤n。

NOIP 2012 提高组 第二天 第二题

2022.2.20 新增一组 hack 数据

实现代码:

cpp 复制代码
#include<iostream>
#include<cstring>
#include<cstdio> 
using namespace std;
int n,m;
int diff[1000011],need[1000011],rest[1000011],r[1000011],l[1000011],d[1000011];
bool isok(int x)
{
    memset(diff,0,sizeof(diff));
    for(int i=1;i<=x;i++)
    {
        diff[l[i]]+=d[i];
        diff[r[i]+1]-=d[i]; 
    }
    for(int i=1;i<=n;i++)
    {
        need[i]=need[i-1]+diff[i];
        if(need[i]>rest[i])return 0;
    }
    return 1;
} 
int main()
{
    
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&rest[i]);
    for(int i=1;i<=m;i++)scanf("%d%d%d",&d[i],&l[i],&r[i]);
    int begin=1,end=m; 
    if(isok(m)){cout<<"0";return 0;}
    while(begin<end)
    {
        int mid=(begin+end)/2;
        if(isok(mid))begin=mid+1;
        else end=mid;
    }
    cout<<"-1"<<endl<<begin;
}
相关推荐
贾斯汀玛尔斯1 小时前
每天学一个算法--DFS / BFS
算法·深度优先·宽度优先
郝学胜-神的一滴1 小时前
epoll 边缘触发 vs 水平触发:从管道到套接字的深度实战
linux·服务器·开发语言·c++·网络协议·unix
cpp_25011 小时前
P1877 [HAOI2012] 音量调节
数据结构·c++·算法·动态规划·题解·洛谷·背包dp
Gary Studio2 小时前
基于PMSM理论研究加实践
算法
AI人工智能+电脑小能手2 小时前
【大白话说Java面试题】【Java基础篇】第9题:HashMap根据key查询元素的时间复杂度是多少
java·开发语言·数据结构·后端·面试·哈希算法·哈希表
invicinble2 小时前
对于java面向对象的知识
java·开发语言
2501_930707782 小时前
使用C#代码在 PowerPoint 中创建组合图表
开发语言·c#·powerpoint
木子墨5162 小时前
LeetCode 热题 100 精讲 | 矩阵与图论进阶篇:矩阵置零 · 螺旋矩阵 · 旋转图像 · 搜索二维矩阵 II · 岛屿数量 · 腐烂的橘子
c++·算法·leetcode·矩阵·力扣·图论
干洋芋果果2 小时前
前端学python
开发语言·前端·python