2021/4/18模拟赛

考试的时候

T1

给出 n n n个矩阵的左上角和右下角的坐标,如果这个矩形和其他矩形没有公共部分,则可以扩展,求最多有几个矩形可以扩展。
第一档数据是 n ≤ 2500 n≤2500 n2500,不知道算不算什么提示有没有什么暴力的方法是可以卡着这个过的。但是感觉可以先把答案设为 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 n20 15 15 15分和 n ≤ 30 n≤30 n30 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。嘿嘿嘿~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值