7.17海亮集训NOIP模拟赛题解
A
有幸找到原题洛谷P4053
一般长得像dp的,但数据范围又很大,dp会TLE,MLE的题就可以考虑反悔贪心了
当然是因为我用dp没做出来然后放弃了
先把结尾从小到大排序,因为容量必须是要一直递增的
维护多余的时间p,若当前所需要的时间小于p,找到当前已经做了的任务中的最大值
如果把老任务换成当前的新任务能够节约时间,即新任务的时间小于当前已经做了的任务中的最大值
那么用新任务代替老任务,即p=p+q.top()-a[i].a;
怎么维护最大值?优先队列。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=1.5e5+5;
void read(LL& x){
char c;
bool f=0;
while((c=getchar())<48) f|=(c==45);
x=c-48;
while((c=getchar())>47) x=x*10+c-48;
x=(f ? -x : x);
return;
}
struct task{
LL a,b;
};
bool cmp(task a,task b){
return a.b<b.b;
}
task a[maxn];
priority_queue<LL> q;
LL n;
int main(){
//freopen("sky.in","r",stdin);
//freopen("sky.out","w",stdout);
read(n);
for(int i=1;i<=n;i++){
read(a[i].a),read(a[i].b);
}
sort(a+1,a+n+1,cmp);
int ans=0;
LL p=0;
for(int i=1;i<=n;i++){
p+=a[i].b-a[i-1].b;
if((!q.empty())&&p<a[i].a&&a[i].a<q.top()){
p=p+q.top()-a[i].a;
q.pop();
q.push(a[i].a);
}
else if(a[i].a<=p){
p-=a[i].a,++ans;
q.push(a[i].a);
}
}
printf("%d",ans);
return 0;
}
B
把题先放在这里吧
数学题暂时没看懂

官解

C

如果对于一个网格点,能够快速找到包含这个点的所有矩形的矩形交,那就可以直接遍历每个点求解了
网格图并不大,可以用二维数组,用差分维护每个矩形上下左右四条边,并记录每个点向上,向下,向左,向右所遇到的第一条边就可以了
矩形交的面积计算如下(r[i][j]-l[i][j]+1)*(d[i][j]-u[i][j]+1)
#include<bits/stdc++.h>
using namespace std;
const int maxn=2005;
void read(int& x){
char c;
bool f=0;
while((c=getchar())<48) f|=(c==45);
x=c-48;
while((c=getchar())>47) x=x*10+c-48;
x=(f ? -x : x);
return;
}
struct node{
int u,d,l,r;
};
node a[maxn][maxn];
int u[maxn][maxn],d[maxn][maxn],l[maxn][maxn],r[maxn][maxn];
int n,m,k;
int main(){
//freopen("rec.in","r",stdin);
//freopen("rec.out","w",stdout);
read(n),read(m),read(k);
int x1,y1,x2,y2;
for(int i=1;i<=k;i++){
read(x1),read(y1),read(x2),read(y2);
++a[x1][y1].u,--a[x1][y2+1].u;
++a[x2][y1].d,--a[x2][y2+1].d;
++a[x1][y1].l,--a[x2+1][y1].l;
++a[x1][y2].r,--a[x2+1][y2].r;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
a[i][j].u=a[i][j-1].u+a[i][j].u;
a[i][j].d=a[i][j-1].d+a[i][j].d;
a[i][j].l=a[i-1][j].l+a[i][j].l;
a[i][j].r=a[i-1][j].r+a[i][j].r;
}
}
memset(u,-1,sizeof(u));
memset(d,-1,sizeof(d));
memset(l,-1,sizeof(l));
memset(r,-1,sizeof(r));
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
u[i][j]=(a[i][j].u ? i : u[i-1][j]);
}
}
for(int i=n;i>=1;i--){
for(int j=1;j<=m;j++){
d[i][j]=(a[i][j].d ? i : d[i+1][j]);
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
l[i][j]=(a[i][j].l ? j : l[i][j-1]);
}
}
for(int i=1;i<=n;i++){
for(int j=m;j>=1;j--){
r[i][j]=(a[i][j].r ? j : r[i][j+1]);
}
}
int ans=1e9+1;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(l[i][j]<0||r[i][j]<0||u[i][j]<0||d[i][j]<0) continue;
ans=min(ans,(r[i][j]-l[i][j]+1)*(d[i][j]-u[i][j]+1));
}
}
printf("%lld",ans);
return 0;
}
被巨佬hack掉了qwq,又要重新订正了
重新订正
如下数据会hack该程序:
21 21 5
9 1 9 11
1 12 10 12
10 10 21 10
11 11 11 21
1 1 21 21
这幅图大概长这样:

(注:每个点表示覆盖这个点的矩形个数)
原因是四个矩形的四条边把程序迷惑住了,误判了中心的伪矩形
考虑哈希,把每个由同一矩形覆盖的点都异或上一个相同的随机数,由此会得到许多块
用dfs求连通块,然后判断该连通块的上下左右四条边是否包含在原来矩形的边中
我觉得原题解描述的更加清楚:

具体见代码注释
#include<bits/stdc++.h>
using namespace std;
const int maxn=2005;
mt19937 rng(time(0));
void read(int& x){
char c;
bool f=0;
while((c=getchar())<48) f|=(c==45);
x=c-48;
while((c=getchar())>47) x=x*10+c-48;
x=(f ? -x : x);
return;
}
int p[maxn][maxn];
int u[maxn][maxn],d[maxn][maxn],l[maxn][maxn],r[maxn][maxn];
bool vis[maxn][maxn];
int wx[4]={0,0,-1,1},wy[4]={-1,1,0,0};
int n,m,k;
void dfs(int x,int y,int& mx,int& my,int& cnt){
++cnt;
vis[x][y]=1;
mx=max(mx,x),my=max(my,y);
for(int i=0;i<4;i++){
int xi=x+wx[i],yi=y+wy[i];
if(xi>=1&&xi<=n&&yi>=1&&yi<=n&&p[x][y]==p[xi][yi]&&!vis[xi][yi]){
dfs(xi,yi,mx,my,cnt);
}
}
}
int main(){
//freopen("rec.in","r",stdin);
//freopen("rec.out","w",stdout);
read(n),read(m),read(k);
int x1,y1,x2,y2;
for(int i=1;i<=k;i++){
read(x1),read(y1),read(x2),read(y2);
++u[x1][y1],--u[x1][y2+1];
++d[x2][y1],--d[x2][y2+1];
++l[x1][y1],--l[x2+1][y1];
++r[x1][y2],--r[x2+1][y2];
int j=rng();
p[x1][y1]^=j,p[x1][y2+1]^=j,p[x2+1][y1]^=j,p[x2+1][y2+1]^=j;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
u[i][j]+=u[i][j-1],d[i][j]+=d[i][j-1];
l[i][j]+=l[i-1][j],r[i][j]+=r[i-1][j];
p[i][j]=p[i][j]^p[i-1][j]^p[i][j-1]^p[i-1][j-1];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
u[i][j]=(u[i][j] ? 1 : 0);
d[i][j]=(d[i][j] ? 1 : 0);
l[i][j]=(l[i][j] ? 1 : 0);
r[i][j]=(r[i][j] ? 1 : 0);
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
u[i][j]=u[i][j-1]+u[i][j];
d[i][j]=d[i][j-1]+d[i][j];
l[i][j]=l[i-1][j]+l[i][j];
r[i][j]=r[i-1][j]+r[i][j];
}
}
int ans=1e9+1,ansi;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(!vis[i][j]){
x1=i,y1=j,x2=-1,y2=-1,ansi=0;
dfs(x1,y1,x2,y2,ansi);
if(u[x1][y2]-u[x1][y1-1]==y2-y1+1&&\
d[x2][y2]-d[x2][y1-1]==y2-y1+1&&\
l[x2][y1]-l[x1-1][y1]==x2-x1+1&&\
r[x2][y2]-r[x1-1][y2]==x2-x1+1&&\ //由于u,d,l,r已经被更新为1,0的前缀和,若区间内1的数量相等,则说明该边是有在原边中的
ansi==(x2-x1+1)*(y2-y1+1)){ //防止连通块是畸形的情况,x2,y2表示的是连通块中最大的x,y值,若该式子满足,一定能说明这是矩形
ans=min(ans,ansi);
}
}
}
}
printf("%d",ans);
return 0;
}
E
努力补题中

浙公网安备 33010602011771号