A. 數字三角形
沒看到拍列,對著自己造的錯樣例改半天。填數,由上往下都向左下填,可以保證有解
點選檢視程式碼
#include<bits/stdc++.h>
const int maxn=550;
using namespace std;
int a[maxn][maxn],n,flag,cnt,maxx,mi;
struct lsx
{
int x,id;
bool operator < (const lsx &a) const
{
return x>a.x;
}
}p[maxn];
void solve(int x,int y,int p)
{
// cout<<x<<" "<<y<<" "<<cnt<<" "<<p<<endl;
if(x<1||x>n||y>x||y<1)return ;
if(flag==1) return ;
a[x][y]=p;
cnt--;
if(cnt==0)
{
flag=1;
return;
}
if(!a[x][y-1])solve(x,y-1,p);
if(!a[x+1][y])solve(x+1,y,p);
if(!a[x-1][y])solve(x-1,y,p);
if(!a[x][y+1])solve(x,y+1,p);
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>p[i].x,a[i][i]=p[i].x,p[i].id=i;
if(p[i].x>maxx)maxx=p[i].x,mi=i;
}
for(int i=1;i<=n;i++)
{
flag=0;
cnt=p[i].x;
solve(p[i].id,p[i].id,p[i].x);
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=i;j++)
{
cout<<a[i][j]<<" ";
}
cout<<'\n';
}
return 0;
}
/*
4
4 2 1 3
*/
B. 那一天她離我而去
按邊暴搜可以得到 \(n=m\) 的23分,加個剪枝用 \(vector\) 存圖可以得到76分(所以為啥前向星只有37)
考慮如何構成一個環,列舉與1相連的出環兒子和入環兒子,因為編號之間的二進位制肯定有一位不一樣
所以考慮列舉位數,每次將1向這一位是0的連邊,這一位是1的向 \(n+1\) 連邊,跑1- \(n+1\) 的最短路
可以保證每一對都跑到
點選檢視程式碼
#include<bits/stdc++.h>
const int maxn=1e5+10;
using namespace std;
int T,n,m,head[maxn],nxt[maxn],to[maxn],val[maxn],tot;
int vis[10010],dis[10010],a[maxn],v[maxn],cnt;
int f[maxn],t[maxn],V[maxn],sum,ans;
inline void add(int x,int y,int z)
{
to[++tot]=y;
val[tot]=z;
nxt[tot]=head[x];
head[x]=tot;
}
priority_queue<pair<int,int> >q;
void lsx(int s)
{
fill(vis+1,vis+n+2,0);
fill(dis+1,dis+n+2,1e9);
dis[s]=0;
q.push({0,s});
while(q.size())
{
int x=q.top().second;
q.pop();
if(vis[x])continue;
vis[x]=1;
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(dis[y]>dis[x]+val[i])
{
dis[y]=dis[x]+val[i];
q.push({-dis[y],y});
}
}
}
}
int main()
{
// freopen("leave.in","r",stdin);
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>T;
while(T--)
{
sum=cnt=0;;
cin>>n>>m;
for(int i=1,x,y,z;i<=m;i++)
{
cin>>x>>y>>z;
if(x==1||y==1)
{
if(x==1)a[++cnt]=y,v[cnt]=z;
else a[++cnt]=x,v[cnt]=z;
}
else
{
f[++sum]=x,t[sum]=y,V[sum]=z;
}
}
int len=0;
for(int i=1;i<=cnt;i++)
{
for(int j=20;j>=0;j--)
{
if((1<<j)&a[i])
{
len=max(len,j);
break;
}
}
}
ans=1e9;
for(int i=len;i>=0;i--)
{
memset(head,0,sizeof head);
tot=0;
for(int j=1;j<=cnt;j++)
{
if((1<<i)&a[j])add(1,a[j],v[j]);
else add(a[j],n+1,v[j]);
}
for(int j=1;j<=sum;j++)
{
add(f[j],t[j],V[j]);
add(t[j],f[j],V[j]);
}
lsx(1);
ans=min(ans,dis[n+1]);
}
cout<<(ans==1e9?-1:ans)<<'\n';
}
return 0;
}
C. 哪一天她能重回我身邊
抽象思路題,正面牌向背面牌連邊權為1的邊,再反向連一個邊權為0的邊,翻一張牌相當於把邊反向,那就是求最小次數
把每張正面的牌的出度變為1,每個聯通塊獨立求答案,方案數是各聯通塊答案之積,對於每個聯通塊來說,邊數大於點數
肯定有一個點出度大於1,跑換根dp,第一次求向下指的邊權為1的邊個數,讓這些邊都變成向上的即可保證每個點出度都
不大於1,再跑第二遍dp更新其他點,只會更新兩點之間的邊,換根之後原來不用反的現在要反,原來用的現在不用。如果
聯通塊不是樹的話,就找環,然後拆環取兩個方向最小值即可,記得加上拆掉的那邊
點選檢視程式碼
#include<bits/stdc++.h>
#define ll long long
const int maxn=2e5+10;
const int mod=998244353;
using namespace std;
int T,n,m,head[maxn],nxt[maxn<<1],to[maxn<<1],val[maxn<<1],tot;
int a[maxn],s,t,pos,sum;
bool vis[maxn],flag;
ll f[maxn],g[maxn],fi,en,ans1,ans2,num;
void add(int x,int y,int z)
{
to[++tot]=y;
val[tot]=z;
nxt[tot]=head[x];
head[x]=tot;
}
void pre()
{
tot=1,flag=0,ans1=0,ans2=1;
memset(head,0,sizeof head);
memset(vis,0,sizeof vis);
}
int tt;
void calc(int x)
{
vis[x]=1;
fi++;
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
en++;
if(vis[y])continue;
calc(y);
}
}
void dfs(int x,int fa)
{
vis[x]=1,f[x]=0;
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==fa)continue;
if(!vis[y])
{
dfs(y,x);
f[x]+=f[y]+val[i];
}
else s=x,t=y,pos=i;
}
}
void solve(int x,int fa)
{
a[++sum]=g[x];
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==fa) continue;
if(i==pos||i==(pos^1))continue;
g[y]=g[x]+(val[i]?-1:1);
solve(y,x);
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>T;
while(T--)
{
tt+=10;
cin>>n;
pre();
for(int i=1,x,y;i<=n;i++)
{
cin>>x>>y;
add(x,y,1);
add(y,x,0);
}
for(int i=1;i<=2*n;i++)
{
if(!vis[i])
{
fi=en=0;
calc(i);
if(en/2>fi)
{
flag=1;
break;
}
}
}
// exit(tt);
if(flag)
{
cout<<"-1 -1"<<'\n';
continue;
}
memset(vis,0,sizeof vis);
for(int i=1;i<=2*n;i++)
{
if(!vis[i])
{
s=t=pos=-1;num=sum=0;
// memset(a,0,sizeof a);
dfs(i,0);g[i]=f[i];
solve(i,0);
if(s==-1)
{
sort(a+1,a+1+sum);
for(int j=1;j<=sum;j++)
{
if(a[j]!=a[1])break;
num++;
}
ans1+=a[1];
}
else
{
pos%=2;
if(g[s]+pos==g[t]+(pos^1))num=2;
else num=1;
ans1+=min(g[s]+pos,g[t]+(pos^1));
}
ans2=ans2*num%mod;
}
}
cout<<ans1<<" "<<ans2<<'\n';
}
return 0;
}
D. 單調區間
這裡直接搬學長題解了,%%%
題解圖片
點選檢視程式碼
#include<bits/stdc++.h>
const int inf=0x3f3f3f;
const int maxn=2e5+10;
using namespace std;
int a[maxn],n,f[maxn][2],last;
long long ans=0;
void solve(int l)
{
f[l][0]=inf;f[l][1]=-inf;
for(int i=l+1;i<=n;i++)
{
int x=-inf,y=inf;
if(f[i-1][0]!=-inf)
{
if(a[i]>a[i-1])x=max(x,f[i-1][0]);
if(a[i]<f[i-1][0])y=min(y,a[i-1]);
}
if(f[i-1][1]!=inf)
{
if(a[i]<a[i-1])y=min(y,f[i-1][1]);
if(a[i]>f[i-1][1])x=max(x,a[i-1]);
}
if(f[i][1]==y&&f[i][0]==x)break;
else
{ f[i][1]=y;
f[i][0]=x;
}
if(f[i][0]==-inf&&f[i][1]==inf)
{
last=i-1;
break;
}
}
ans+=last-l+1;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
last=n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=n;i>=1;i--)solve(i);
cout<<ans;
return 0;
}