20201121 模拟赛总结

题目PDF,提取码 iqmz

\(100+60+15=175\text{pts}\)

打了三个暴力居然苟了个 rk1。。不可思议

T1

原题:洛谷 P1292

由裴蜀定理,可知第一问答案为 \(\gcd(a,b)\)。于是第二问答案就变成了求满足 \(ax+by=\gcd(a,b)\)\(x,y\),exgcd 求解然后二分调整一下答案使得答案满足条件即可。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define int long long
int exgcd(int a,int b,int &x,int &y)
{
	if(b==0)
	{
		x=1;y=0;
		return a;
	}
	int ans=exgcd(b,a%b,x,y);
	int t=x;
	x=y;
	y=t-a/b*y;
	return ans;
}
signed main()
{
	freopen("pour.in","r",stdin);
	freopen("pour.out","w",stdout);
	int a,b,x,y;
	scanf("%lld %lld",&a,&b);
	if(b>a) swap(a,b);
	if(a%b==0)
	{
		printf("%lld\n0 1",b);
		return 0;
	}
	int gg;
	printf("%lld\n",gg=exgcd(a,b,x,y));
	int ans=0,l=-1e9,r=1e9;
	int ml=b/gg,mr=a/gg;
	while(l<=r)
	{
		int mid=(l+r)/2;
		if(x+mid*ml<=0 && y-mid*mr>0) 
		{
			ans=mid;
			l=mid+1;
		}
		else r=mid-1;
	}
	x=x+ans*ml;y=y-ans*mr;
	printf("%lld %lld",-x,y);
	return 0;
}

T2

在洛谷上传了数据,可以点这里提交。

60pts

\(\mathcal O(n^2m^2)\) 枚举左上角和右下角,二位前缀和预处理然后 \(\mathcal O(1)\) 判断是否可行。

PS:这个做法被 lht 加上几个剪枝卡过去了……而且跑的比正解还快……

100pts

三重循环,第一重枚举长方形的上面的边,第二重枚举下面的边,第三重从左到右扫一遍看看能得到的最大左右距离(可以通过前缀和实现)。

时间复杂度 \(\mathcal O(n^2 m)\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=400;
char s[N+10][N+10];
int sum[N+10][N+10];
int main()
{
	int n,m;
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
	for(int i=1;i<=n;i++) 
	{
		for(int j=1;j<=m;j++)
		{
			sum[i][j]=sum[i-1][j];
			sum[i][j]+=(s[i][j]=='X'); 
		}
	}
//	for(int i=1;i<=n;i++)
//	{
//		for(int j=1;j<=m;j++) printf("%d ",sum[i][j]);
//		putchar('\n');
//	}
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=i;j<=n;j++)
		{
			int mx=0,cnt=0;
			for(int k=1;k<=m;k++)
			{
				if(sum[j][k]-sum[i-1][k]==0) cnt++;
				else cnt=0;
				mx=max(mx,cnt);
			}
			if(mx) ans=max(ans,(j-i+1)*2+mx*2);
		}
	}
	printf("%d",ans-1);
	return 0;
}

T3

原题:bzoj 2143

吐槽一波题面,Input 里 \(A_{i,j}\)\(B_{i,j}\) 写反了。。

首先暴力连边肯定是不行的,会 MLE+TLE。

考虑拆点。按照每个点 \((x,y)\) 的弹射能力 \(B_{x,y}\)\((x,y)\) 拆成 \(B_{x,y}+1\) 个点,记作 \((x,y,0),(x,y,1),\cdots,(x,y,B_{x,y})\),第三维的意义是到达点 \((x,y)\) 的时候还剩多少能量,这里能量的的意思是每到达一个点 \((i,j)\),能量就会增加 \(B_{i,j}\),跳了多少距离能量就相应地减少多少。Dijkstra 过程中每次到 \((x,y,0)\) 就只能考虑跳到 \((x,y,B_{x,y})\),其他情况考虑向上、向下、向左、向右和原地不动即可。

这题套路有点类似 10 月 17 日模拟赛的 T2,但又没做出来 /kk

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<queue>
using namespace std;
const int INF=0x3f3f3f3f;
inline void read(int &x)
{
	x=0; int f=1;
	char c=getchar();
	while(c<'0' || c>'9')
	{
		if(c=='-') f=-1;
		c=getchar();
	}
	while(c>='0' && c<='9')
	{
		x=(x<<1)+(x<<3)+(c^48);
		c=getchar();
	}
	x*=f;
}
const int nxt[5][2]={{0,1},{1,0},{0,-1},{-1,0},{0,0}};
int n,m;
struct node
{
	int x,y,d,en; //distance, energy
	node() {}
	node(int tx,int ty,int te,int td) {x=tx;y=ty;d=td;en=te;}
	bool operator < (const node &x) const {return d>x.d;}
}; //priority_queue
const int N=150;
int dis[N+10][N+10][N*2+10];
int a[N+10][N+10],b[N+10][N+10];
bool vis[N+10][N+10][N*2+10];
inline void dij(int Sx,int Sy) // S -> T
{
	memset(vis,0,sizeof(vis));
	priority_queue<node> que;
	memset(dis,0x3f,sizeof(dis));
	dis[Sx][Sy][b[Sx][Sy]]=a[Sx][Sy];
	que.push(node(Sx,Sy,b[Sx][Sy],a[Sx][Sy]));
	while(!que.empty())
	{
		node head=que.top(); que.pop();
		// printf("head:(%d, %d), %d\n",head.x,head.y,head.en);
		if(vis[head.x][head.y][head.en]) continue;
		vis[head.x][head.y][head.en]=true;
		if(head.en>0)
		{
			for(int k=0;k<=4;k++)
			{
				int tx=head.x+nxt[k][0],ty=head.y+nxt[k][1];
				if(tx<1 || tx>n || ty<1 || ty>m) continue;//dis[][][]:(x, y)  energy: z
				if(dis[head.x][head.y][head.en]<dis[tx][ty][head.en-1])
				{
					dis[tx][ty][head.en-1]=dis[head.x][head.y][head.en];
					que.push(node(tx,ty,head.en-1,dis[tx][ty][head.en-1]));
				}
			}
		}
		else
		{
			if(dis[head.x][head.y][0]+a[head.x][head.y]<dis[head.x][head.y][b[head.x][head.y]])
			{
				dis[head.x][head.y][b[head.x][head.y]]=dis[head.x][head.y][0]+a[head.x][head.y];
				que.push(node(head.x,head.y,b[head.x][head.y],dis[head.x][head.y][b[head.x][head.y]]));
			}
		}
	}
}
//a[][]: cost
//b[][]: energy
typedef pair<int,int> pii;
int main()
{
	freopen("zhber.in","r",stdin);
	freopen("zhber.out","w",stdout);
	read(n);read(m);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
		{
			read(b[i][j]);
			b[i][j]=min(b[i][j],n+m-2);
		}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			read(a[i][j]);
	pii xx,yy,zz;
	read(xx.first);read(xx.second);read(yy.first);read(yy.second);read(zz.first);read(zz.second);
	int d[3][3];memset(d,0,sizeof(d));
	// printf("(%d, %d), (%d, %d), (%d, %d)\n",xx.first,xx.second,yy.first,yy.second,zz.first,zz.second);
	dij(xx.first,xx.second);d[0][1]=dis[yy.first][yy.second][0];d[0][2]=dis[zz.first][zz.second][0];
	dij(yy.first,yy.second);d[1][0]=dis[xx.first][xx.second][0];d[1][2]=dis[zz.first][zz.second][0];
	dij(zz.first,zz.second);d[2][0]=dis[xx.first][xx.second][0];d[2][1]=dis[yy.first][yy.second][0];
	int X=d[1][0]+d[2][0],Y=d[0][1]+d[2][1],Z=d[0][2]+d[1][2];
	// printf("d[][]:\n");
	// for(int i=0;i<3;i++)
	// {
	// 	for(int j=0;j<3;j++) printf("%d ",d[i][j]);
	// 		putchar('\n');
	// }
 	if(X>=INF && Y>=INF && Z>=INF) puts("NO");
	else
	{
		if(X<=Y && X<=Z) printf("X\n%d",X);
		else if(Y<=X && Y<=Z) printf("Y\n%d",Y);
		else if(Z<=X && Z<=Y) printf("Z\n%d",Z);
	}
	return 0;
}
posted @ 2020-11-21 13:49  zzt1208  阅读(214)  评论(2编辑  收藏  举报