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;
}