【比赛】高一下二调
板子题合集。
唯一的难点在于没告诉我们要考试 (悲)
但是 \(AK\) 力 (喜)
T1 交通管制
题面
最短路。
正解应该是记录路径,然后将路径上每一条边 \(\times \ 2\) 后跑最短路,统计答案
但可以直接遍历所有的边,统计答案
赛时打的 \(SPFA\) 没被卡,过了 😃
Update:赛后新添了 5 组 Hack 数据,告诉我们有很多重边,不能用堆优化 Dij,所以下面这三个代码都过不了了
感谢 @wwppcc 提供的(现在不是)正解代码
“正解”
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=251;
int n,m,tot,mx[N],ed[N][N],l[N],lf[N],lt[N],tp;
ll dis[N],ans,output;
bool vis[N];
priority_queue <pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q;
void djs()
{
q.push({0,1});
memset(dis,0x3f,sizeof(dis));
dis[1]=0;
while(!q.empty())
{
int st=q.top().second;
q.pop();
if(vis[st])continue;
vis[st]=1;
for(int i=1;i<=n;i++)
{
if(!vis[i]&&ed[st][i]&&dis[i]>dis[st]+ed[st][i])
{
dis[i]=dis[st]+ed[st][i];
l[i]=st;
q.push({dis[i],i});
}
}
}ans=dis[n];
}
void find(int x)
{
if(l[x])
{
lf[++tp]=l[x];
lt[tp]=x;
find(l[x]);
}else return;
}
void d(int f,int t)
{
q.push({0,1});
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
int lst=ed[f][t];
ed[f][t]*=2;
ed[t][f]*=2;
dis[1]=0;
while(!q.empty())
{
int st=q.top().second;
q.pop();
if(vis[st])continue;
vis[st]=1;
for(int i=1;i<=n;i++)
{
if(!vis[i]&&ed[st][i]&&dis[i]>dis[st]+ed[st][i])
{
dis[i]=dis[st]+ed[st][i];
l[i]=st;
q.push({dis[i],i});
}
}
}
output=max(output,dis[n]-ans);
ed[f][t]=lst;
ed[t][f]=lst;
}
void init()
{
scanf("%d%d",&n,&m);
int f,t,w;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&f,&t,&w);
ed[f][t]=w;
ed[t][f]=w;
}djs();
find(n);
for(int i=1;i<=tp;i++)
{
d(lf[i],lt[i]);
}printf("%lld",output);
}
int main()
{
freopen("traffic.in","r",stdin);
freopen("traffic.out","w",stdout);
init();
return 0;
}
SPFA
#include<bits/stdc++.h>
using namespace std;
const int N=255;
struct edge{
int next,to,w;
}e[250005*2];
int h[N],cnt;
inline void add(int u,int v,int w){
e[++cnt]={h[u],v,w};
h[u]=cnt;
}
int n,m,x,y,z;
int dis[N],vis[N];
inline void spfa(int x){
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
queue<int> q;
dis[x]=0;vis[x]=1;
q.push(x);
while(!q.empty()){
int u=q.front();
q.pop();
for(register int i=h[u];i;i=e[i].next){
int to=e[i].to;
if(dis[to]>dis[u]+e[i].w){
dis[to]=dis[u]+e[i].w;
if(!vis[to]){
q.push(to);
vis[to]=1;
}
}
}
vis[u]=0;
}
}
int main(){
freopen("traffic.in","r",stdin);
freopen("traffic.out","w",stdout);
scanf("%d%d",&n,&m);
for(register int i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);add(y,x,z);
}
spfa(1);
int last=dis[n],ans=0;
for(register int i=1;i<=m*2;i+=2){
e[i].w*=2;e[i+1].w*=2;
spfa(1);
ans=max(ans,dis[n]);
e[i].w/=2;e[i+1].w/=2;
}
printf("%d",ans-last);
fclose(stdin);
fclose(stdout);
return 0;
}
Dijkstra
#include<bits/stdc++.h>
using namespace std;
const int N=255;
typedef pair<int,int> pii;
struct edge{
int next,to,w;
}e[250005*2];
int h[N],cnt;
inline void add(int u,int v,int w){
e[++cnt]={h[u],v,w};
h[u]=cnt;
}
int n,m,x,y,z;
int dis[N],vis[N];
inline void dij(int x){
priority_queue<pii,vector<pii>,greater<pii> > p;
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
p.push({0,x});
dis[x]=0;
while(!p.empty()){
int u=p.top().second;
p.pop();
if(vis[u])continue;
vis[u]=1;
for(int i=h[u];i;i=e[i].next){
int to=e[i].to;
if(!vis[to]&&dis[to]>dis[u]+e[i].w){
dis[to]=dis[u]+e[i].w;
p.push({dis[to],to});
}
}
}
}
int main(){
freopen("traffic.in","r",stdin);
freopen("traffic.out","w",stdout);
scanf("%d%d",&n,&m);
for(register int i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);add(y,x,z);
}
dij(1);
int last=dis[n],ans=0;
for(register int i=1;i<=m*2;i+=2){
e[i].w*=2;e[i+1].w*=2;
dij(1);
ans=max(ans,dis[n]);
e[i].w/=2;e[i+1].w/=2;
}
printf("%d",ans-last);
fclose(stdin);
fclose(stdout);
return 0;
}
感谢 @DHYY 提供的朴素 Dij 过法
正解
#include<bits/stdc++.h>
#define fo(x,y,z) for(int (x)=(y);(x)<=(z);(x)++)
#define fu(x,y,z) for(int (x)=(y);(x)>=(z);(x)--)
inline int qr()
{
char ch=getchar();int x=0,f=1;
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
return x*f;
}
#define qr qr()
using namespace std;
const int Ratio=0;
const int N=3005;
const int maxint=INT_MAX;
int n,m,cnt;
int dh[N][N];
int t1,t2;
int biaoji[N];
bool kkk;
vector<int>v;
namespace work1
{
bool yz[N];
int yy[N];
void sol()
{
memset(yy,0x3f,sizeof yy);
yy[1]=0;
fo(i,2,n)
{
int k=0;
fo(j,1,n)
if(yy[j]<yy[k]&&!yz[j])
k=j;
yz[k]=true;
fo(j,1,n)
// if(!yz[j])
// yy[j]=min(yy[j],yy[k]+dh[k][j]);
if(yy[k]+dh[k][j]<yy[j])
{
yy[j]=yy[k]+dh[k][j];
biaoji[j]=k;
}
}
// fo(i,1,n)标记正确已验
// cout<<i<<' '<<biaoji[i]<<endl;
t1=yy[n];
}//t1正确已验
void findmax(int x)
{
v.push_back(x);
if(x==1)
return;
findmax(biaoji[x]);
}
void pd()
{
if(n==3&&m==3&&dh[1][2]==3)
{
cout<<2;
kkk=true;
}
}
}
namespace work2
{
bool yz[N];
int yy[N];
void sol()
{
memset(yy,0x3f,sizeof yy);
memset(yz,0,sizeof yz);
yy[1]=0;
fo(i,2,n)
{
int k=0;
fo(j,1,n)
if(yy[j]<yy[k]&&!yz[j])
k=j;
yz[k]=true;
fo(j,1,n)
if(!yz[j])
yy[j]=min(yy[j],yy[k]+dh[k][j]);
}
// cout<<yy[n]<<endl;
if(yy[n]!=yy[n+1])
t2=max(t2,yy[n]);
}
}
int main()
{
freopen("traffic.in","r",stdin);
freopen("traffic.out","w",stdout);
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
n=qr,m=qr;
memset(dh,0x3f,sizeof dh);
fo(i,1,m)
{
int a=qr,b=qr,c=qr;
if(!dh[a][b]||c<dh[a][b])
dh[a][b]=dh[b][a]=c;
}
work1::sol();
// cout<<t1<<endl;
work1::findmax(n);
int fla,nnn=-maxint;
int qi,zhong;
t2=-maxint;
work1::pd();
if(kkk)
return Ratio;
// cout<<t2<<endl;
// for(auto i:v)
// {
// if(i==n)
// {
// fla=i;
// continue;
// }
// if(nnn<dh[i][fla])
// qi=i,zhong=fla,nnn=dh[i][fla];
// // cout<<i<<' '<<fla<<' '<<nnn<<endl;
// fla=i;
// }
for(auto i:v)
{
// cout<<i<<' '<<fla<<endl;
if(i==n)
{
fla=i;
continue;
}
// if(dh[i][fla]==nnn)
// {
// cout<<"{}{"<<endl;
nnn=dh[i][fla];
dh[i][fla]*=2;
dh[fla][i]=dh[i][fla];
work2::sol();
dh[i][fla]=dh[fla][i]=nnn;
// }
fla=i;
}
// work2::sol();
printf("%d\n",t2-t1);
fclose(stdin);
fclose(stdout);
return Ratio;
}
T2 教室安排
题面
二分水题。
二分距离,按贪心的思想,距离够了就放。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
typedef long long ll;
ll a[N];
int n,m;
bool check(ll x){
int num=1,now=1;
for(int i=2;i<=n;i++){
if(a[i]-a[now]>=x){
now=i;
num++;
if(num>=m)return 1;
}
}
return num>=m;
}
int main(){
freopen("classroom.in","r",stdin);
freopen("classroom.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
sort(a+1,a+1+n);
ll l=1,r=1e9+5,mid;
while(l<=r){
mid=(l+r)>>1;
if(check(mid))l=mid+1;
else r=mid-1;
}
cout<<r;
fclose(stdin);
fclose(stdout);
return 0;
}
T3 招商
题面
单调栈板子。
左右扫两次单调栈,求出一个建筑向左右的最大扩展距离,乘上高度即可。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=4e5+5;
typedef long long ll;
ll n,h[N],sum=0;
ll l[N],r[N];
stack<ll> s;
int main(){
freopen("post.in","r",stdin);
freopen("post.out","w",stdout);
scanf("%lld",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&h[i]);
l[i]=r[i]=1;
}
for(int i=1;i<=n;i++){
while(!s.empty()&&h[s.top()]>=h[i]){
l[i]=l[i]+l[s.top()];
s.pop();
}
s.push(i);
}
while(!s.empty())s.pop();
for(int i=n;i>=1;i--){
while(!s.empty()&&h[s.top()]>=h[i]){
r[i]=r[i]+r[s.top()];
s.pop();
}
s.push(i);
}
for(int i=1;i<=n;i++){
sum=max(sum,h[i]*(l[i]+r[i]-1));
}
cout<<sum;
fclose(stdin);
fclose(stdout);
return 0;
}
T4 帝国大会
题面
LCA 板子。
dfs 序和 SPFA 预处理 , 然后查找两个数的最近公共祖先 ,\(ans \ = \ dis[x] + dis[y] - 2 \times dis[LCA]\) 。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
struct edge{
int next,to,w;
}e[N*2];
int h[N],cnt;
void add(int u,int v,int w){
e[++cnt]={h[u],v,w};
h[u]=cnt;
}
int in[N],out[N],dep[N],num,n,m,q,x,y,z;
int f[N][35];
void dfs(int x,int fa){
in[x]=++num;
dep[x]=dep[fa]+1;
f[x][0]=fa;
for(int i=h[x];i;i=e[i].next){
int to=e[i].to;
if(to==fa)continue;
if(!in[to]){
dfs(to,x);
}
}
out[x]=num;
}
inline int lca(int x,int y){
if(dep[x]<dep[y])swap(x,y);
int d=dep[x]-dep[y];
for(int i=0;i<30;i++){
if(d&(1<<i))x=f[x][i];
}
if(x==y)return x;
for(int i=29;i>=0;i--){
if(f[x][i]!=f[y][i]){
x=f[x][i];
y=f[y][i];
}
if(f[x][0]==f[y][0])break;
}
return f[x][0];
}
int dis[N],vis[N];
inline void spfa(int x){
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
queue<int> q;
dis[x]=0;vis[x]=1;
q.push(x);
while(!q.empty()){
int u=q.front();
q.pop();
for(register int i=h[u];i;i=e[i].next){
int to=e[i].to;
if(dis[to]>dis[u]+e[i].w){
dis[to]=dis[u]+e[i].w;
if(!vis[to]){
q.push(to);
vis[to]=1;
}
}
}
vis[u]=0;
}
}
int main(){
freopen("meeting.in","r",stdin);
freopen("meeting.out","w",stdout);
scanf("%d%d",&n,&m);
lca(n,m);
if(n==1){
scanf("%d",&q);
for(int i=1;i<=q;i++){
scanf("%d%d",&x,&y);
printf("0\n");
}
return 0;
}
for(int i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);add(y,x,z);
}
dfs(1,0);
for(int j=1;j<30;j++){
for(int i=1;i<=n;i++){
f[i][j]=f[f[i][j-1]][j-1];
}
}
spfa(1);
scanf("%d",&q);
for(int i=1;i<=q;i++){
scanf("%d%d",&x,&y);
int k=lca(x,y);
if(k==x||k==y){//赛事觉得需要分类,其实不用,直接打下边那句就行
printf("%d\n",abs(dis[x]-dis[y]));
}
else printf("%d\n",dis[x]+dis[y]-2*dis[k]);
}
fclose(stdin);
fclose(stdout);
return 0;
}