考试的时候
T1
给出
n
n
n个矩阵的左上角和右下角的坐标,如果这个矩形和其他矩形没有公共部分,则可以扩展,求最多有几个矩形可以扩展。
第一档数据是
n
≤
2500
n≤2500
n≤2500,不知道算不算什么提示有没有什么暴力的方法是可以卡着这个过的。但是感觉可以先把答案设为
n
n
n,左端点排序,然后标记被覆盖的点,如果这个点已经被覆盖,则
n
−
−
;
n--;
n−−;然后重新看一下最左边那个矩形有没有重的。
突然感觉不是太可行,因为后面的矩形可能会与前面的中间隔一段距离,然后又与其他矩形重合。
可以先把所有覆盖的点扫一遍,每次扫到这个点就让这个点的值
+
1
+1
+1,然后重新再扫一遍,如果该点的值不为
1
1
1,则说明此矩形一定与其他的有公共边,而且突然又注意到矩形不能互相覆盖,所以只扫边框应该就行了。然后就去照着这个思路码了。
#include<bits/stdc++.h>
using namespace std;
#define N 25010
int read()
{
int num=0;bool flag=1;char c=getchar();
for(;c<'0'||c>'9';c=getchar()) if(c=='-') flag=0;
for(;c>='0'&&c<='9';c=getchar()) num=(num<<1)+(num<<3)+c-'0';
return flag?num:-num;
}
int flag[1000][1000],ans,n;bool chong[2];
struct ylsdjx{int a,b,c,d;}yls[N];
int main()
{
n=read();ans=n;
for(int i=1;i<=n;i++)
{
yls[i].a=read();yls[i].b=read();yls[i].c=read();yls[i].d=read();
for(int j=yls[i].a+1;j<yls[i].c;j++) {flag[j][yls[i].b]++;flag[j][yls[i].d]++;}
for(int j=yls[i].b;j<=yls[i].d;j++) {flag[yls[i].a][j]++;flag[yls[i].b][j]++;}
}
for(int i=1;i<=n;i++)
{
chong[0]=0;
for(int j=yls[i].a+1;j<yls[i].c;j++) {if((flag[j][yls[i].b]>1)||(flag[j][yls[i].d]>1)) {chong[0]=1;break;}}
if(chong[0]==0) for(int j=yls[i].b;j<=yls[i].d;j++) {if((flag[yls[i].a][j]>1)||(flag[yls[i].b][j]>1)) {chong[0]=1;break;}}
if(chong[0]==1) ans--;
}
cout<<ans;
}
写出了极其丑陋的暴力,然而连样例也没过,然后突然发现坐标是在 [ 0 , 1 6 ] [0,1^6] [0,16]的范围内,众所周知,不看数据范围就写代码无异于是耍流氓。这个方法显然会炸掉。所以我觉得还是应该左端点排序然后一个一个扫可能更优。然后就陷进去思考该怎么做细节,没想出来,开始做 T 2 T2 T2。
T2
一摞
n
n
n个圆形喷泉,层给出半径和容积,
q
q
q次询问:向第
i
i
i个里面倒
j
j
j个水,输出水最终会到达哪一层。
先暴力模拟一下。
#include<bits/stdc++.h>
using namespace std;
#define N 100010
int shang,v[N],r[N],a,b,n,q;
int read()
{
int num=0;bool flag=1;char c=getchar();
for(;c<'0'||c>'9';c=getchar()) if(c=='-') flag=0;
for(;c>='0'&&c<='9';c=getchar()) num=(num<<1)+(num<<3)+c-'0';
return flag?num:-num;
}
void ask(int x,int y)
{
y-=v[x];shang=x;
if(y<=0) {printf("%d\n",x);return ;}
for(int i=x;;i++)
{
if(r[i]>r[shang]) {y-=v[i];shang=i;}
if(y<=0) {if(i>n)puts("0");else printf("%d\n",i);return ;}
}return ;
}
int main()
{
n=read();q=read();r[n+1]=999999999;v[n+1]=999999999;
for(int i=1;i<=n;i++) {r[i]=read();v[i]=read();}
for(int i=1;i<=q;i++) {a=read();b=read();ask(a,b);}
return 0;
}
应该能用单调队列之类的优化,但是先看
T
3
T3
T3吧。
但是应该可以无脑线段树,或者前缀和优化一下,要是打完
4
4
4个暴力还有时间就实践。
T3
三人分蛋糕,蛋糕为圆环形且被切成
n
n
n段,每人只能要连着的一段蛋糕,求分得蛋糕最少的人最多能得到的蛋糕是多少。
看了看题,然后上厕所呼吸一口新鲜空气。
上厕所
虽说敢看了
T
3
T3
T3但是脑子里还是想的
T
1
T1
T1。应该可以存一下竖着的每个边的起始点和结束点,横着的每条边的左端点和右端点,这样应给不至于爆数据吧。
s
o
r
t
sort
sort完一下后每次向后查找会不会有重的,给每个矩形一个
i
d
id
id,让
f
l
a
g
[
i
d
]
=
1
flag[id]=1
flag[id]=1来标记这个矩形是和其他有重合的。
然后又写下了极其丑陋的代码。
#include<bits/stdc++.h>
using namespace std;
#define N 25002
int len,q,w,e,r,n,ans;bool flag[N];
int read()
{
int num=0;bool flag=1;char c=getchar();
for(;c<'0'||c>'9';c=getchar()) if(c=='-') flag=0;
for(;c>='0'&&c<='9';c=getchar()) num=(num<<1)+(num<<3)+c-'0';
return flag?num:-num;
}
struct hengzhe{int z,y,hang,id;}heng[N<<1];
struct shuzhe{int s,x,lie,id;}shu[N<<1];
bool mycmp1(hengzhe orz,hengzhe qwq) {return (orz.hang<qwq.hang);}
bool mycmp2(shuzhe orz,shuzhe qwq) {return (orz.lie<qwq.lie);}
int main()
{
n=read();len=0;
for(int i=1;i<=n;i++) {len++;heng[len].id=i;shu[len].id=i;len++;heng[len].id=i;shu[len].id=i;}len=0;
for(int i=1;i<=n;i++)
{
q=read();w=read();e=read();r=read();
len++;heng[len].z=q;heng[len].y=e;shu[len].s=r;shu[len].x=w;heng[len].hang=r;shu[len].lie=q;
len++;heng[len].z=q;heng[len].y=e;shu[len].s=r;shu[len].x=w;heng[len].hang=w;shu[len].lie=e;
}
sort(heng+1,heng+1+n+n,mycmp1);sort(shu+1,shu+1+n+n,mycmp2);
for(int i=1;i<=len;i++)
{
for(int j=i+1;;j++)
{
if(heng[j].hang!=heng[i].hang) break;
if((heng[i].z<=heng[j].z&&heng[i].y>=heng[j].z)||(heng[i].z<=heng[j].y&&heng[i].y>=heng[j].y)||(heng[i].z<=heng[j].z&&heng[i].y>=heng[j].y)||(heng[i].z>=heng[j].z&&heng[j].y<=heng[j].y))
{flag[heng[i].id]=1;flag[heng[j].id]=1;}
}
for(int j=i+1;;j++)
{
if(shu[i].lie!=shu[j].lie) break;
if((shu[i].s>=shu[j].s&&shu[i].x<=shu[j].s)||(shu[i].s>=shu[j].x&&shu[i].x<=shu[j].x)||(shu[i].s>=shu[j].s&&shu[i].x<=shu[j].x)||(shu[i].s<=shu[j].s&&shu[i].x>=shu[j].x))
{flag[shu[i].id]=1;flag[shu[j].id]=1;}
}
}
for(int i=1;i<=n;i++) if(flag[i]==0) ans++;
printf("%d",ans);
return 0;
}
过样例了,但是只有一个样例,还是很慌啊。
于是奖励自己上个厕所呼吸下新鲜空气
T4
一开始没有发
T
4
T4
T4,所以刚看题。
又双叒叕是分蛋糕,岳老师先拿走一块蛋糕,然后从刘老师开始,刘老师拿一个,岳老师拿一个。除了一开始岳老师拿走一个蛋糕是随便想拿哪个拿哪个以外,剩下的拿蛋糕的时候只能拿相邻两边蛋糕至少有一个被拿走的蛋糕,而刘老师每次会拿走可拿走蛋糕中最大的,而岳老师都行,由于岳老师得到蛋糕后是打算和学生们分的,所以求岳老师最多得到多少蛋糕。
感觉是区间
D
P
DP
DP?
一维表示蛋糕的起始点,一维表示吃到分到第几回合?
先实践一下试试,曾有伟人言:做不出就加一维。
根据一般的这种环的题的做法,我先把蛋糕复制成原来的三倍。
由于身上衣服的樟脑丸味道太过于浓郁,所以我在教室门口的地上蹲着演算到
D
P
DP
DP方程,然后突然悟道其实刘老师拿哪个蛋糕算是相当固定的了,每次拿最大的,这样的话把问题转化为让刘老师拿到的蛋糕最少可能更好求。最后减一下就行了。
只剩20分钟了,还是没法求出来,深搜打暴力吧。
void dfs(int x,int y,int zuo,int you)
x
x
x表示当前回合数,用于结束递归,
y
y
y表示刘老师拿了多少蛋糕,
z
u
o
zuo
zuo表示左端点,
y
o
u
you
you表示右端点,然后以
O
(
n
4
)
O(n^4)
O(n4)的方式显然可以过掉
n
≤
20
n≤20
n≤20的
15
15
15分和
n
≤
30
n≤30
n≤30的
45
45
45分,但是由于前期太贪了,当我悟道
d
f
s
dfs
dfs就能
60
60
60分时已经没时间了。π_π
考完讨论发现自己的时间复杂度算错了,应该是
2
n
2^n
2n才对。
成绩出来后,只得了 70 70 70, T 1 T1 T1得了 40 40 40,因为比较玄学,所以同样是最大的数据,有 T L E TLE TLE也有 34 m s 34ms 34ms,然后最近一长段时间在校 o j oj oj打模拟赛都没有掉过 R e a t i n g Reating Reating,这次直接掉了 25 25 25,从榜上被踢出来了,真难受啊。但其实主要还是我最近都没有怎么写题,省选后的 3 3 3个学长退役我心里还是很乱,文化课那边快期中考试了我还是啥都不会就很自闭。
然后是讲题
T
1
T1
T1的思路我和myf大佬的一样,而且时间复杂度都不稳定,都可能被同一种情况卡掉。但是具体代码实现方面我有些丑陋,而且肯能有点扫描线的思想在里面,剪枝以后骗到了
90
90
90分。
#include<bits/stdc++.h>
using namespace std;
#define N 25002
int len,q,w,e,r,n,ans;bool flag[N];
int read()
{
int num=0;bool flag=1;char c=getchar();
for(;c<'0'||c>'9';c=getchar()) if(c=='-') flag=0;
for(;c>='0'&&c<='9';c=getchar()) num=(num<<1)+(num<<3)+c-'0';
return flag?num:-num;
}
struct hengzhe{int z,y,hang,id;}heng[N<<1];
struct shuzhe{int s,x,lie,id;}shu[N<<1];
bool mycmp1(hengzhe orz,hengzhe qwq) {return ((orz.hang==qwq.hang&&orz.z<qwq.z)||(orz.hang<qwq.hang));}
bool mycmp2(shuzhe orz,shuzhe qwq) {return ((orz.lie<qwq.lie)||(orz.lie==qwq.lie&&orz.s>qwq.s));}
int main()
{
n=read();len=0;
for(int i=1;i<=n;i++) {len++;heng[len].id=i;shu[len].id=i;len++;heng[len].id=i;shu[len].id=i;}len=0;
for(int i=1;i<=n;i++)
{
q=read();w=read();e=read();r=read();
len++;heng[len].z=q;heng[len].y=e;shu[len].s=r;shu[len].x=w;heng[len].hang=r;shu[len].lie=q;
len++;heng[len].z=q;heng[len].y=e;shu[len].s=r;shu[len].x=w;heng[len].hang=w;shu[len].lie=e;
}
sort(heng+1,heng+1+n+n,mycmp1);sort(shu+1,shu+1+n+n,mycmp2);
for(int i=1;i<=len;i++)
{
for(int j=i+1;;j++)
{
if(heng[j].hang!=heng[i].hang) break;
if(heng[j].y>heng[i].z)
if((heng[i].z<=heng[j].z&&heng[i].y>=heng[j].z)||(heng[i].z<=heng[j].y&&heng[i].y>=heng[j].y)||(heng[i].z<=heng[j].z&&heng[i].y>=heng[j].y)||(heng[i].z>=heng[j].z&&heng[j].y<=heng[j].y))
{flag[heng[i].id]=1;flag[heng[j].id]=1;}
}
for(int j=i+1;;j++)
{
if(shu[i].lie!=shu[j].lie) break;
if(shu[j].s<shu[i].x) break;
if((shu[i].s>=shu[j].s&&shu[i].x<=shu[j].s)||(shu[i].s>=shu[j].x&&shu[i].x<=shu[j].x)||(shu[i].s>=shu[j].s&&shu[i].x<=shu[j].x)||(shu[i].s<=shu[j].s&&shu[i].x>=shu[j].x))
{flag[shu[i].id]=1;flag[shu[j].id]=1;}
}
}
for(int i=1;i<=n;i++) if(flag[i]==0) ans++;
printf("%d",ans);
return 0;
}
然而我又加了许多常数级别的优化
#include<bits/stdc++.h>
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
using namespace std;
#define N 25002
int len,q,w,e,r,n,ans;bool flag[N];
int read()
{
int num=0;bool flag=1;char c=getchar();
for(;c<'0'||c>'9';c=getchar()) if(c=='-') flag=0;
for(;c>='0'&&c<='9';c=getchar()) num=(num<<1)+(num<<3)+c-'0';
return flag?num:-num;
}
struct ios{
inline char read(){
static const int IN_LEN=1<<18|1;
static char buf[IN_LEN],*s,*t;
return (s==t)&&(t=(s=buf)+fread(buf,1,IN_LEN,stdin)),s==t?-1:*s++;
}
template <typename _Tp> inline ios & operator >> (_Tp&x){
static char c11,boo;
for(c11=read(),boo=0;!isdigit(c11);c11=read()){
if(c11==-1)return *this;
boo|=c11=='-';
}
for(x=0;isdigit(c11);c11=read())x=x*10+(c11^'0');
boo&&(x=-x);
return *this;
}
}io;
void write(int x)
{
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar((x%10)^48);
}//??
struct hengzhe{int z,y,hang,id;}heng[N<<1];
struct shuzhe{int s,x,lie,id;}shu[N<<1];
bool mycmp1(hengzhe orz,hengzhe qwq) {return ((orz.hang==qwq.hang&&orz.z<qwq.z)||(orz.hang<qwq.hang));}
bool mycmp2(shuzhe orz,shuzhe qwq) {return ((orz.lie<qwq.lie)||(orz.lie==qwq.lie&&orz.s>qwq.s));}
int main()
{
// ios::sync_with_stdio(false);
// cin.tie(NULL);
// cout.tie(NULL);
freopen("expand.in","r",stdin);freopen("expand.out","w",stdout);
// n=read();
// scanf("%d",&n);
io>>n;len=0;
for(int i=1;i<=n;i++) {len++;heng[len].id=i;shu[len].id=i;len++;heng[len].id=i;shu[len].id=i;}len=0;
for(int i=1;i<=n;i++)
{
// q=read();w=read();e=read();r=read();
// scanf("%d%d%d%d",&q,&w,&e,&r);
io>>q>>w>>e>>r;
len++;heng[len].z=q;heng[len].y=e;shu[len].s=r;shu[len].x=w;heng[len].hang=r;shu[len].lie=q;
len++;heng[len].z=q;heng[len].y=e;shu[len].s=r;shu[len].x=w;heng[len].hang=w;shu[len].lie=e;
}
sort(heng+1,heng+1+n+n,mycmp1);sort(shu+1,shu+1+n+n,mycmp2);
for(int i=1;i<=len;i++)
{
for(int j=i+1;;j++)
{
if(heng[j].hang!=heng[i].hang) break;
if(heng[j].y>heng[i].z)
if((heng[i].z<=heng[j].z&&heng[i].y>=heng[j].z)||(heng[i].z<=heng[j].y&&heng[i].y>=heng[j].y)||(heng[i].z<=heng[j].z&&heng[i].y>=heng[j].y)||(heng[i].z>=heng[j].z&&heng[j].y<=heng[j].y))
{flag[heng[i].id]=1;flag[heng[j].id]=1;}
}
for(int j=i+1;;j++)
{
if(shu[i].lie!=shu[j].lie) break;
if(shu[j].s<shu[i].x) break;
if((shu[i].s>=shu[j].s&&shu[i].x<=shu[j].s)||(shu[i].s>=shu[j].x&&shu[i].x<=shu[j].x)||(shu[i].s>=shu[j].s&&shu[i].x<=shu[j].x)||(shu[i].s<=shu[j].s&&shu[i].x>=shu[j].x))
{flag[shu[i].id]=1;flag[shu[j].id]=1;}
}
}
for(int i=1;i<=n;i++) if(flag[i]==0) ans++;
write(ans);
return 0;
}
虽说还是 T T T掉了,但是整个程序运行时间从 1439 m s 1439ms 1439ms变成了 1349 m s 1349ms 1349ms,于是我正好这个不是多组数据而且我超时的正好是唯一的一个 n = 20001 n=20001 n=20001。嘿嘿嘿~