10.5 模拟赛
前言
业精于勤荒于嬉,行成于思毁于随
正文(模拟赛)
卦象:凶
感受:开 T1,第一眼读错题,白费 20min;第二眼简单区间 DP,没打算写,然后先去开 T2,为爆零埋下了伏笔。九点开 T2,一顿手模之后发现链式结构,此时九点半,开写 T2。写到比赛结束都没有调出来,最后 T1 也没来得及写,原地爆炸
T1
简单区间 DP 题,记 \(f_{l,r}\) 表示区间 \([l,r]\) 内的答案,其实未必要合并成一个数,我们只关心单次合并对答案的贡献
转移显然枚举断点,只在 \(len-1 \equiv 0 \pmod {k-1}\) 的时候进行区间合并的贡献统计
也没什么细节问题,时间复杂度 \(O(n^3/k)\)
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=505;
int n,k,a[N],s[N],f[N][N];
inline void chkmn(int &x,int y){x=min(x,y);return;}
inline int ask(int l,int r){return s[r]^s[l-1];}
signed main(){
freopen("merge.in","r",stdin);
freopen("merge.out","w",stdout);
cin>>n>>k;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)s[i]=s[i-1]^a[i];
memset(f,0x3f,sizeof(f));
for(int i=1;i<=n;i++)f[i][i]=0;
for(int len=2;len<=n;len++){
for(int l=1;l+len-1<=n;l++){
int r=l+len-1;
for(int p=l;p<=r-1;p+=(k-1))chkmn(f[l][r],f[l][p]+f[p+1][r]);
if((len-1)%(k-1)==0)f[l][r]+=ask(l,r);
}
}
cout<<f[1][n]<<'\n';
return 0;
}
T2
发现链式结构,被二分创飞了
点击查看代码
#include<bits/stdc++.h>
#define pii pair<int,int>
#define fi first
#define se second
#define mkp make_pair
#define vp vector<pii>
#define pb push_back
#define lwbd lower_bound
using namespace std;
const int N=1e6+5;
int n,m,Q,a[N][2];
struct que{int l,r,k,id;}q[N];
pii pre[N][2],mp[N],f[N][2];
vp vec[N<<1],pos[N];int tol;
int rev[N][2];bool vis[N][2];
inline pii fnd(int x,int lim){
int l=0,r=pos[x].size()-1,id=-1;
while(l<=r){
int mid=(l+r)>>1;
if(pos[x][mid].fi<=lim)l=mid+1,id=mid;
else r=mid-1;
}
return (id==-1?mkp(-1,-1):pos[x][id]);
}
inline pii fnd2(vp vec,int x){
int l=0,r=vec.size()-1,res=-1;
while(l<=r){
int mid=(l+r)>>1;
if(vec[mid].fi>=x)r=mid-1,res=mid;
else l=mid+1;
}
return vec[res];
}
int main(){
freopen("perm.in","r",stdin);
freopen("perm.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m>>Q;
for(int i=1;i<=m;i++)cin>>a[i][0]>>a[i][1];
for(int i=1;i<=m;i++){
if(a[i][0]==a[i][1])continue;
pos[a[i][0]].pb(mkp(i,0)),pos[a[i][1]].pb(mkp(i,1));
}
for(int i=1;i<=m;i++){
if(a[i][0]==a[i][1])continue;
pre[i][0]=mp[a[i][0]],mp[a[i][0]]=mkp(i,0);
pre[i][1]=mp[a[i][1]],mp[a[i][1]]=mkp(i,1);
}
for(int i=1;i<=m;i++)f[i][0]=pre[i][1],f[i][1]=pre[i][0];
for(int i=m;i>=1;i--){
if(a[i][0]==a[i][1])continue;
for(int o=0;o<=1;o++){
pii p=mkp(i,o);
if(vis[p.fi][p.se])continue;
tol++;
while(p.fi){
vec[tol].pb(p),rev[p.fi][p.se]=tol,vis[p.fi][p.se]=true;
p=f[p.fi][p.se];
}
}
}
for(int i=1;i<=tol;i++)sort(vec[i].begin(),vec[i].end());
while(Q--){
int l,r,k;cin>>l>>r>>k;
pii idx=fnd(k,r);
if(idx.fi==-1||idx.fi<l){cout<<k<<'\n';continue;}
int c=rev[idx.fi][idx.se];
pii ans=fnd2(vec[c],l);
cout<<a[ans.fi][ans.se^1]<<'\n';
}
return 0;
}
T3
初始化 \(f_i \gets + \infty\)
如果当前有向图上存在无出度的点 \(v\),对于所有的 \((u,v) \in E\),进行 \(\operatorname{chkmn}(f_u,\max(f_v-p,r))\)
否则,挑出 \(r\) 最大的边 \((u,v,r,p)\),进行 \(\operatorname{chkmn}(f_u,r)\)
重复执行“如果……否则……”,直到所有边都被删除
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define pii pair<int,int>
#define fi first
#define se second
#define mkp make_pair
#define vi vector<int>
#define vn vector<NODE>
#define pb push_back
using namespace std;
const int N=2e5+5,INF=9e18,V=1e18;
int n,m,out[N],f[N],q[N],hd=1,tl=0;
struct NODE{int v,r,p,id;};vn G[N];
struct edge{int u,v,r,p;}e[N];
bool mrk[N];
inline bool cmp(edge x,edge y){return x.r>y.r;}
inline void chkmn(int &x,int y){x=min(x,y);return;}
inline void work(){
while(hd<=tl){
int u=q[hd++];
for(auto E:G[u]){
int v=E.v,r=E.r,p=E.p,id=E.id;
if(mrk[id])continue;
chkmn(f[v],max(r,f[u]-p));
mrk[id]=true;out[v]--;
if(!out[v])q[++tl]=v;
}
}
return;
}
signed main(){
freopen("walk.in","r",stdin);
freopen("walk.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1,u,v,r,p;i<=m;i++){
cin>>u>>v>>r>>p;out[u]++;
e[i]={u,v,r,p};
}
for(int i=1;i<=n;i++)f[i]=INF;
for(int i=1;i<=n;i++)
if(!out[i])q[++tl]=i;
sort(e+1,e+m+1,cmp);
for(int i=1;i<=m;i++){
int u=e[i].u,v=e[i].v,r=e[i].r,p=e[i].p;
G[v].pb({u,r,p,i});
}
work();
for(int i=1;i<=m;i++){
if(mrk[i])continue;
int u=e[i].u,r=e[i].r;chkmn(f[u],r);
mrk[i]=true;out[u]--;
if(!out[u]){q[++tl]=u;work();}
}
for(int i=1;i<=n;i++)cout<<(f[i]>V?-1:f[i])<<' ';
cout<<'\n';
return 0;
}
T4
留坑待填
小结
补题效率不错,就是赛时表现太抽象了
后记
世界孤立我任它奚落
完结撒花!