$vjudge\ CSP-S$专题专练题解
照例先放个链接$QwQ$
$A$
$QwQ$之前写过题解辣.
重新说下趴,就给横坐标纵坐标也开点,然后每个点连向对应横纵坐标边权为$0$,相邻横坐标点之间连边,相邻纵坐标点之间连边,跑个最短路就完事$QwQ$
还有一种想法是先按$x$排序相邻相连,再按$y$排序相邻相连.因为两个不相邻的一定能通过两个相邻达到,所以是对的.
$upd:$
我是真的自闭,,,之前做这题的时候$bzoj$在维护,我就在$darkbzoj$上交,过了.
然后今天在$bzoj$上交,不是$TLE$就是$MLE$,就很自闭.
调了很久之后发现是数组开大了:)
$wzbl$
#include<bits/stdc++.h>
using namespace std;
#define il inline
#define lf double
#define gc getchar()
#define mp make_pair
#define int long long
#define P pair<int,int>
#define t(i) edge[i].to
#define w(i) edge[i].wei
#define ri register int
#define rc register char
#define rb register bool
#define lowbit(x) (x&(-x))
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i)
#define e(i,x) for(ri i=head[x];i;i=edge[i].nxt)
#define lbh(x) lower_bound(sth+1,sth+1+h_cnt,x)-sth
#define lbl(x) lower_bound(stl+1,stl+1+l_cnt,x)-stl const int N=5e5+10;
int n,h_cnt,sth[N],l_cnt,stl[N],ed_cnt,head[N<<1],S,T,dis[N<<1],vis[N<<1];
struct node{int x,y;}nod[N];
struct ed{int to,nxt,wei;}edge[N<<3];
priority_queue< P,vector<P>,greater<P> >Q; il int read()
{
rc ch=gc;ri x=0;rb y=1;
while(ch!='-' && (ch>'9' || ch<'0'))ch=gc;
if(ch=='-')ch=gc,y=0;
while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc;
return y?x:-x;
}
il void ad(ri x,ri y,ri z){/*printf("%d %d %d\n",x,y,z);*/edge[++ed_cnt]=(ed){x,head[y],z};head[y]=ed_cnt;}
il void dij()
{
memset(dis,63,sizeof(dis));dis[S]=0;Q.push(mp(0,S));
while(!Q.empty())
{
ri nw=Q.top().second;Q.pop();if(vis[nw])continue;vis[nw]=1;
//printf("nw=%d dis=%d\n",nw,dis[nw]);
e(i,nw)if(dis[t(i)]>dis[nw]+w(i))dis[t(i)]=dis[nw]+w(i),Q.push(mp(dis[t(i)],t(i)));
}
} signed main()
{
//freopen("4152.in","r",stdin);freopen("4152.out","w",stdout);
n=read();rp(i,1,n)nod[i]=(node){sth[++h_cnt]=read(),stl[++l_cnt]=read()};
sort(sth+1,sth+1+h_cnt);h_cnt=unique(sth+1,sth+h_cnt+1)-sth-1;rp(i,1,n)nod[i].x=lbh(nod[i].x);
sort(stl+1,stl+1+l_cnt);l_cnt=unique(stl+1,stl+l_cnt+1)-stl-1;rp(i,1,n)nod[i].y=lbl(nod[i].y);
rp(i,2,h_cnt)ad(i,i-1,sth[i]-sth[i-1]),ad(i-1,i,sth[i]-sth[i-1]);
rp(i,2,l_cnt)ad(i+h_cnt,i-1+h_cnt,stl[i]-stl[i-1]),ad(i-1+h_cnt,i+h_cnt,stl[i]-stl[i-1]);
rp(i,1,n){ri t1=i+h_cnt+l_cnt,t2=nod[i].y+h_cnt;ad(t1,nod[i].x,0),ad(nod[i].x,t1,0),ad(t1,t2,0),ad(t2,t1,0);}
S=1+h_cnt+l_cnt;T=n+h_cnt+l_cnt;dij();printf("%lld\n",dis[T]);
return 0;
}
$B$
题目大意可以上洛谷康康.注意下是有向边就成$/kel$
考虑到一个强联通分量内肯定全部可以拿走,所以跑个$tarjan$缩点,就成了一个$DAG$.
然后随便$dp$一下就完事,$QwQ$
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define t(i) edge[i].to
#define w(i) edge[i].wei
#define rp(i,x,y) for(int i=x;i<=y;++i)
#define e(i,x) for(int i=head[x];i;i=edge[i].nxt) const int N=1e6+10;
int n,m,S,bl[N],bl_cnt,fr[N],to[N],wei[N],dat[N]; namespace pre
{
int head[N],ed_cnt,dfn[N],low[N],dfn_cnt,stck[N],top;
bool instck[N];
struct ed{int to,nxt,wei;}edge[N];
void ad(int x,int y,int z){edge[++ed_cnt]=(ed){x,head[y],z};head[y]=ed_cnt;}
void tarjan(int nw)
{
dfn[nw]=low[nw]=++dfn_cnt;stck[++top]=nw;instck[nw]=1;
e(i,nw)
{
if(!dfn[t(i)])tarjan(t(i)),low[nw]=min(low[nw],low[t(i)]);
else if(instck[t(i)])low[nw]=min(low[nw],dfn[t(i)]);
}
if(dfn[nw]==low[nw])
{
++bl_cnt;
while(stck[top]^nw){bl[stck[top]]=bl_cnt;instck[stck[top--]]=0;}bl[nw]=bl_cnt,instck[nw]=0,--top;
}
}
void main()
{scanf("%lld%lld",&n,&m);rp(i,1,m){scanf("%lld%lld%lld",&fr[i],&to[i],&wei[i]);ad(to[i],fr[i],wei[i]);}scanf("%lld",&S);rp(i,1,n)if(!dfn[i])tarjan(i);}
}
namespace work
{
int head[N],ed_cnt,f[N],as,qwq[N],sum[N],qwq_cnt;
struct ed{int to,nxt,wei;}edge[N];
queue<int>Q;
int cal(int w){int t=sqrt(2*w+0.25)-0.5;return w*(t+1)-(t+1)*(t+2)*t/6;}
void ad(int x,int y,int z){edge[++ed_cnt]=(ed){x,head[y],z};head[y]=ed_cnt;}
int dp(int nw){if(f[nw])return f[nw];e(i,nw)f[nw]=max(f[nw],dp(t(i))+w(i));return f[nw]+=dat[nw];}
void main(){rp(i,1,m)if(bl[fr[i]]^bl[to[i]])ad(bl[to[i]],bl[fr[i]],wei[i]);else dat[bl[fr[i]]]+=cal(wei[i]);printf("%lld\n",dp(bl[S]));}
} signed main(){pre::main();work::main();return 0;}
$C$
考虑对$a$中每个位置$i$,记录一个它之后的最近的序列$p$中对应的最近的下一个位置.
然后发现对每个位置,往后跳$n-1$次就能跑完一个排列嘛.
所以对每个位置求一个$ans_i$表示它跑完一个排列最早在哪儿结束,这个倍增随便搞下就出来了.
然后每次询问就查询$[l,r]$里的$ans_{min}$和$r$的大小关系,$st$表维护一波就完事$QwQ$
一个小$trick$是如果你是记录的$ans_i$表示向前跑最晚在哪儿结束就可以不用考虑初始化的问题了$/kel$
(虽然我写的向后跑$/kel$
注意区分下$n$和$m$,,,我因为这个$WA$了两三次$/dk$
#include<bits/stdc++.h>
using namespace std;
#define my(i,x,y) for(int i=x;i>=y;--i)
#define rp(i,x,y) for(int i=x;i<=y;++i) const int N=2e5+10;
int n,m,q,p[N],rk[N],a[N],nxt[N][22],st[N][22],lg[N];
vector<int>V[N]; int query(int l,int r){int len=r-l+1;return min(st[l][lg[len]],st[r-(1<<lg[len])+1][lg[len]]);} int main()
{
scanf("%d%d%d",&n,&m,&q);memset(nxt,63,sizeof(nxt));memset(st,63,sizeof(st));rp(i,1,m)st[i][0]=i;lg[0]=-1;rp(i,1,m)lg[i]=lg[i>>1]+1;
rp(i,1,n)scanf("%d",&p[i]),rk[p[i]]=i;;p[0]=p[n];
rp(i,1,m)
{
scanf("%d",&a[i]);int dat=p[rk[a[i]]-1];
while(V[dat].size()){int nw=V[dat].size()-1;nxt[V[dat][nw]][0]=i;V[dat].pop_back();}V[a[i]].push_back(i);
}
rp(i,1,19)rp(j,1,m)if(nxt[j][i-1]<=m)nxt[j][i]=nxt[nxt[j][i-1]][i-1];
int t=n-1;my(i,19,0)if(t>=(1<<i)){rp(j,1,m)if(st[j][0]<=m)st[j][0]=nxt[st[j][0]][i];t-=(1<<i);}
rp(i,1,19)rp(j,1,m-(1<<i)+1)st[j][i]=min(st[j][i-1],st[j+(1<<(i-1))][i-1]);
while(q--){int l,r,pos;scanf("%d%d",&l,&r);pos=query(l,r);printf(pos<=r?"1":"0");}
return 0;
}
$D$
蛮经典的题,在$PPT$上都看到两次辣$QwQ$.
嗷然后因为我第一次看题的时候理解错题意了所以先港下,就这里是线段不是直线鸭$QwQ$
首先说下.因为上方下方其实是差不多做的所以我就只说上方了$QwQ$
考虑枚举哪个颜色不选,然后找到一个极大边界数点就成.
发现直接枚举不太好做,于是把所有点按$y$排序,从高到低加入,每次加入就等价于枚举了颜色和下边界.
左右边界可以在加入的时候顺便按$x$排序加入$set$中,每次查询当前加入点的前驱后继就知道左右边界了.
然后树状数组数点就成.
嗷注意还有一种情况,就是存在对$y$没有限制即两个$x$相邻的点同色.这个在$set$里查下就成$QwQ$
因为多组数据所以注意清零$QwQ$
#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) (x&(-x))
#define my(i,x,y) for(int i=x;i>=y;--i)
#define rp(i,x,y) for(int i=x;i<=y;++i)
#define lb(x) lower_bound(st+1,st+st_cnt+1,x)-st const int N=200000+10;
int n,m,st[N],st_cnt,tr[N],as;
struct node{int col,x,y;}nod[N];
vector<int>V[N];
set<int>S[N];
set<int>::iterator it; void ad(int x){while(x<=st_cnt)++tr[x],x+=lowbit(x);}
int query(int nw){int ret=0;while(nw)ret+=tr[nw],nw-=lowbit(nw);return ret;} int main()
{
//freopen("4548.in","r",stdin);freopen("4548.out","w",stdout);
int T;scanf("%d",&T);
while(T--)
{
as=0;st_cnt=0;scanf("%d%d",&n,&m);rp(i,1,n){int x,y,z;scanf("%d%d%d",&x,&y,&z);st[++st_cnt]=x,st[++st_cnt]=y;nod[i]=(node){z,x,y};}
sort(st+1,st+1+st_cnt);st_cnt=unique(st+1,st+1+st_cnt)-st-1;rp(i,1,n)nod[i].x=lb(nod[i].x),V[nod[i].y=lb(nod[i].y)].push_back(i);
memset(tr,0,sizeof(tr));rp(i,1,m)S[i].clear(),S[i].insert(0),S[i].insert(st_cnt+1);
rp(i,1,st_cnt)
{
int sz=V[i].size();
rp(k,0,sz-1)
{
int l,r,j=V[i][k];
it=S[nod[j].col].upper_bound(nod[j].x);--it;l=*it;it=S[nod[j].col].lower_bound(nod[j].x);r=*it;as=max(as,query(r-1)-query(l));
}
rp(k,0,sz-1){int j=V[i][k];S[nod[j].col].insert(nod[j].x),ad(nod[j].x);}
}
rp(i,1,m){it=S[i].begin();while((*it)^(st_cnt+1)){int l=*it;++it;as=max(as,query((*it)-1)-query(l));}}
memset(tr,0,sizeof(tr));rp(i,1,m)S[i].clear(),S[i].insert(0),S[i].insert(st_cnt+1);
my(i,st_cnt,1)
{
int sz=V[i].size();
rp(k,0,sz-1)
{
int l,r,j=V[i][k];
it=S[nod[j].col].upper_bound(nod[j].x);--it;l=*it;it=S[nod[j].col].lower_bound(nod[j].x);r=*it;as=max(as,query(r-1)-query(l));
}
rp(k,0,sz-1){int j=V[i][k];S[nod[j].col].insert(nod[j].x),ad(nod[j].x);}
V[i].clear();
}
rp(i,1,m){it=S[i].begin();while((*it)^(st_cnt+1)){int l=*it;++it;as=max(as,query((*it)-1)-query(l));}}
printf("%d\n",as);
}
return 0;
}
$E$
,,,我感觉这题我见过七八遍了.
不想说了$QAQ$
#include<algorithm>
#include<iomanip>
#include<cstring>
#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
#define il inline
#define gc getchar()
#define ri register int
#define rb register bool
#define rc register char
#define rp(i,l,r) for(ri i=l;i<=r;++i)
#define my(i,l,r) for(ri i=l;i>=r;--i) const int N=210;
int n,color[N],cnt[N],f[N][N][N],now,ct,ans; il int read()
{
rc ch=gc;ri x=0;rb y=1;
while(ch!='-' && (ch>'9' || ch<'0'))ch=gc;
if(ch=='-')ch=gc,y=0;
while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc;
return y?x:-x;
}
int bfs(int l,int r,int k)
{
if(f[l][r][k]!=0)return f[l][r][k];if(l>r)return 0;
f[l][r][k]=bfs(l,r-1,0)+(cnt[r]+k)*(cnt[r]+k);
rp(i,l,r-1)if(color[i]==color[r])f[l][r][k]=max(bfs(l,i,cnt[r]+k)+bfs(i+1,r-1,0),f[l][r][k]);
return f[l][r][k];
} int main()
{
// freopen("QAQ.in","r",stdin);freopen("QAQ.out","w",stdout);
ri T=read();
rp(i,1,T)
{
memset(color,0,sizeof(color));memset(f,0,sizeof(f));now=1;n=read();
rp(j,1,n){ct=read();if(ct==color[now])++cnt[now];else{++now;cnt[now]=1;color[now]=ct;}}
ans=bfs(1,now,0);
cout<<"Case "<<i<<": "<<ans<<endl;
}
return 0;
}
$F$
$QwQ$很久很久之前就做过辣.
#include<bits/stdc++.h>
using namespace std;
long long f[100015]={1};
long long read()
{
char ch=getchar();
long long x=0,y=1;
while((ch!='-') && (ch>'9' || ch<'0'))ch=getchar();
if(ch=='-')y=-1,ch=getchar();
while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=getchar();
return x*y;
}
int main()
{
long long c[5];c[1]=read(),c[2]=read(),c[3]=read(),c[4]=read();long long tot=read();
for(long long i=1;i<=4;++i)
for(long long j=c[i];j<=100001;++j)f[j]+=f[j-c[i]];
while(tot>0)
{
tot--;
long long d1=read(),d2=read(),d3=read(),d4=read(),s=read(),ans=f[s];
if((d1+1)*c[1]<=s)ans-=f[s-((d1+1)*c[1])];
if((d2+1)*c[2]<=s)ans-=f[s-((d2+1)*c[2])];
if((d3+1)*c[3]<=s)ans-=f[s-((d3+1)*c[3])];
if((d4+1)*c[4]<=s)ans-=f[s-((d4+1)*c[4])];
if((d1+1)*c[1]+(d2+1)*c[2]<=s)ans+=f[s-((d1+1)*c[1])-(d2+1)*c[2]];
if((d1+1)*c[1]+(d3+1)*c[3]<=s)ans+=f[s-((d1+1)*c[1])-(d3+1)*c[3]];
if((d1+1)*c[1]+(d4+1)*c[4]<=s)ans+=f[s-((d1+1)*c[1])-(d4+1)*c[4]];
if((d2+1)*c[2]+(d3+1)*c[3]<=s)ans+=f[s-((d2+1)*c[2])-(d3+1)*c[3]];
if((d2+1)*c[2]+(d4+1)*c[4]<=s)ans+=f[s-((d2+1)*c[2])-(d4+1)*c[4]];
if((d3+1)*c[3]+(d4+1)*c[4]<=s)ans+=f[s-((d3+1)*c[3])-(d4+1)*c[4]];
if((d1+1)*c[1]+(d2+1)*c[2]+(d3+1)*c[3]<=s)ans-=f[s-((d1+1)*c[1])-(d2+1)*c[2]-(d3+1)*c[3]];
if((d1+1)*c[1]+(d2+1)*c[2]+(d4+1)*c[4]<=s)ans-=f[s-((d1+1)*c[1])-(d2+1)*c[2]-(d4+1)*c[4]];
if((d1+1)*c[1]+(d4+1)*c[4]+(d3+1)*c[3]<=s)ans-=f[s-((d1+1)*c[1])-(d4+1)*c[4]-(d3+1)*c[3]];
if((d4+1)*c[4]+(d2+1)*c[2]+(d3+1)*c[3]<=s)ans-=f[s-((d4+1)*c[4])-(d2+1)*c[2]-(d3+1)*c[3]];
if((d1+1)*c[1]+(d2+1)*c[2]+(d3+1)*c[3]+(d4+1)*c[4]<=s)ans+=f[s-((d1+1)*c[1])-(d2+1)*c[2]-(d3+1)*c[3]-(d4+1)*c[4]];
cout<<ans<<endl;
}
return 0;
}
$G$
没有脑子,不会贪心,说个最暴力的做法趴$QwQ$
考虑类似蔬菜的套路,先按$t_1$排序,然后每栋楼尽量放结尾.
然后珂朵莉树维护下哪些时间能放就完事.$QwQ$
$over$
#include<bits/stdc++.h>
using namespace std;
#define P pair<int,int>
#define mp make_pair
#define rp(i,x,y) for(int i=x;i<=y;++i) const int N=150000+10;
int n,as;
P nod[N];
set<P>S; void split(int x)
{
set<P>::iterator it=S.upper_bound(mp(x+1,0));if(it==S.begin())return;--it;if((*it).second<=x)return;
P tmp=*it;S.erase(it);S.insert(mp(tmp.first,x));if(tmp.second>x)S.insert(mp(x+1,tmp.second));
}
int check(int tim,int ddl)
{
split(ddl);set<P>::iterator it=S.upper_bound(mp(ddl+1,0)),tmp=it;int nw=0;
while(tmp!=S.begin()){--tmp;nw+=(*tmp).second-(*tmp).first+1;if(nw>=tim)break;}
if(nw<tim)return 0;;int t=(*tmp).first+(nw-tim);split(t-1);tmp=S.lower_bound(mp(t,0));while(tmp!=it)S.erase(tmp++);return 1;
} int main()
{
scanf("%d",&n);rp(i,1,n)scanf("%d%d",&nod[i].first,&nod[i].second);sort(nod+1,nod+1+n);
S.insert(mp(1,INT_MAX));rp(i,1,n)as+=check(nod[i].first,nod[i].second);printf("%d\n",as);
return 0;
}
$H$
不难想到肯定优先用数量多的之间配对?
用堆维护下数量就完事.$QwQ$
$QwQQQQQ$注意一个细节,就一定是每次取出来之后只拿一个,不能把第三大的全拿完了$QwQ$
#include<bits/stdc++.h>
using namespace std;
#define mp make_pair
#define P pair<int,int>
#define rp(i,x,y) for(int i=x;i<=y;++i)
#define lb(x) lower_bound(st+1,st+1+st_cnt,x)-st const int N=1e5+10;
int n,r[N],st[N],st_cnt,num[N],as,as1[N],as2[N],as3[N];
priority_queue<P>Q; void print(int x,int y,int z){if(x<y)swap(x,y);if(x<z)swap(x,z);if(y<z)swap(y,z);printf("%d %d %d\n",x,y,z);} int main()
{
scanf("%d",&n);rp(i,1,n)scanf("%d",&r[i]),st[i]=r[i];sort(st+1,st+1+n);st_cnt=unique(st+1,st+1+n)-st-1;rp(i,1,n)++num[lb(r[i])];
rp(i,1,st_cnt)Q.push(mp(num[i],st[i]));
while(Q.size()>2)
{
P t1,t2,t3;t1=Q.top();Q.pop();t2=Q.top();Q.pop();t3=Q.top();Q.pop();
as1[++as]=t1.second,as2[as]=t2.second,as3[as]=t3.second;
--t1.first,--t2.first,--t3.first;if(t1.first)Q.push(t1);if(t2.first)Q.push(t2);if(t3.first)Q.push(t3);
}
printf("%d\n",as);rp(i,1,as)print(as1[i],as2[i],as3[i]);
return 0;
}
$I$
$QwQ$首先一个性质,就这个操作的顺序是无影响的,所以可以强制从小到大决策,最后乘以全排列就完事.
然后考虑剪枝.
注意到它这里分段的时候每段其实是固定的了.
所以在决策第$i$个决策的时候,可以考虑将序列分成$2^{i-1}$段,然后如果每段内部的顺序都是连续且递增的就不要操作.如果有一段内部不满足就把这一段内部的搞下,如果有两段内部不满足就把它们之间搞下,如果有超过两段不满足就直接$GG$了.
核心思想在于由局部推到整体.即因为是从小到大搞的,所以在决策第$i$个的时候,显然$2^{i-2}$长度的序列是有序的了,就只用考虑$2^{i-1}$的序列了$QwQ$.
$over$
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define rp(i,x,y) for(int i=x;i<=y;++i) const int N=1e6+;
int n,m,a[N],fac[],as; bool chck(int len){for(int i=;i<=m;i+=(len<<))if((a[i]+len)^(a[i+len]))return ;return ;}
void swp(int x,int y,int l){rp(i,,l-)swap(a[x+i],a[y+i]);}
void dfs(int len,int cnt)
{
if(len^ && !chck(len>>))return;;if(!(len^m)){as+=fac[cnt];return;}
dfs(len<<,cnt);int p[],gdgs=;
for(int i=;i<=m;i+=(len<<))if((a[i]+len)^a[i+len]){if(!(gdgs^))return;else p[++gdgs]=i,p[++gdgs]=i+len;}
rp(i,,gdgs)rp(j,i+,gdgs)swp(p[i],p[j],len),dfs(len<<,cnt+),swp(p[i],p[j],len);
} signed main(){scanf("%lld",&n);m=<<n;rp(i,,m)scanf("%lld",&a[i]);fac[]=;rp(i,,n)fac[i]=fac[i-]*i;dfs(,);printf("%lld\n",as);return ;}
$J$
听$lyh$说要$A*$?我头铁写了发搜索过了$QwQ$
#include<bits/stdc++.h>
using namespace std;
#define mp make_pair
#define P pair<int,int>
#define rp(i,x,y) for(int i=x;i<=y;++i)
#define lb(x) lower_bound(st+1,st+1+st_cnt,x)-st const int N=50+5,inf=1e9;
int n,m,ed_cnt,as_cnt,as,lk[N][N],sq_cnt,sz[N],rlsz[N],num[N]; int nam_h(int x,int y){return (n<<1|1)*(x-1)+y;}
int nam_l(int x,int y){return (n<<1|1)*(x-1)+y+n;}
void pre()
{
scanf("%d%d",&n,&m);ed_cnt=2*n*(n+1);as=n*n;sq_cnt=0;
rp(i,1,ed_cnt)num[i]=1;rp(i,1,m){int x;scanf("%d",&x);num[x]=0;}
memset(lk,0,sizeof(lk));sq_cnt=0;
rp(i,1,n)
rp(j,1,n-i+1)
rp(k,1,n-i+1)
{
sz[++sq_cnt]=0;rlsz[sq_cnt]=4*i;
rp(p,0,i-1)
{
int t1=nam_h(j,k+p),t2=nam_h(j+i,k+p),t3=nam_l(j+p,k),t4=nam_l(j+p,k+i);//printf(" t1=%d t2=%d t3=%d t4=%d num=%d %d %d %d\n",t1,t2,t3,t4,num[t1],num[t2],num[t3],num[t4]);
lk[sq_cnt][t1]=lk[sq_cnt][t2]=lk[sq_cnt][t3]=lk[sq_cnt][t4]=1;sz[sq_cnt]+=num[t1]+num[t2]+num[t3]+num[t4];
}
//printf("sz[%d]=%d rlsz[%d]=%d\n",sq_cnt,sz[sq_cnt],sq_cnt,rlsz[sq_cnt]);
} }
int fd(){rp(i,1,sq_cnt)if(!(rlsz[i]^sz[i]))return i;return -1;}
void dfs(int stp)
{
if(stp>=as)return;;int nw=fd();if(!(~nw)){as=stp;return;}
rp(i,1,ed_cnt)if(lk[nw][i]){rp(j,1,sq_cnt)if(lk[j][i])--sz[j];dfs(stp+1);rp(j,1,sq_cnt)if(lk[j][i])++sz[j];}
} int main()
{
// freopen("1603.in","r",stdin);freopen("1603.out","w",stdout);
int T;scanf("%d",&T);
while(T--){pre();dfs(0);printf("%d\n",as);}
return 0;
}
$K$
题目大意说给定一个图,每条边有边权,有$K$条边可以把边权变为$0$.问$S$到$T$的路径上最大边权的最小值是多少.
$umm$这个不是一看就二分嘛?考虑二分这个权值$mid$.然后长度大于$mid$的边权设为$1$,小于等于$mid$的设为$0$.跑个最短路就完事.
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
#define t(i) edge[i].to
#define w(i) edge[i].wei
#define rp(i,x,y) for(int i=x;i<=y;++i)
#define e(i,x) for(int i=head[x];i;i=edge[i].nxt) const int N=1000+10,M=10000+10;
int n,m,K,head[N],ed_cnt,dis[N],l=1e9,r;
bool vis[N];
struct ed{int to,nxt,wei;}edge[M<<1];
struct ED{int fr,to,wei;}EDGE[M];
deque<int>Q; void ad(int x,int y,int z){edge[++ed_cnt]=(ed){x,head[y],z};head[y]=ed_cnt;edge[++ed_cnt]=(ed){y,head[x],z};head[x]=ed_cnt;}
int bfs()
{
memset(dis,63,sizeof(dis));dis[1]=0;Q.push_front(1);
while(!Q.empty())
{
int nw=Q.front();Q.pop_front();if(vis[nw])continue;
e(i,nw)if(dis[t(i)]>dis[nw]+w(i)){dis[t(i)]=dis[nw]+w(i);dis[nw]^dis[t(i)]?Q.push_back(t(i)):Q.push_front(t(i));}
}
return dis[n];
}
bool check(int dat)
{
ed_cnt=0;memset(head,0,sizeof(head));memset(vis,0,sizeof(vis));
rp(i,1,m)ad(EDGE[i].fr,EDGE[i].to,(bool)(EDGE[i].wei>dat));
return bfs()<=K;
} int main()
{
//freopen("3662.in","r",stdin);
scanf("%d%d%d",&n,&m,&K);rp(i,1,m)scanf("%d%d%d",&EDGE[i].fr,&EDGE[i].to,&EDGE[i].wei),l=min(l,EDGE[i].wei),r=max(r,EDGE[i].wei);
while(l<r){int mid=(l+r)>>1;if(check(mid))r=mid;else l=mid+1;}printf("%d\n",l);
return 0;
}
随机推荐
- LeetCode54 Spiral Matrix
题目: Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spira ...
- matplotlib绘制热力图
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/jin_tmac/article/deta ...
- SDUT-2054_数据结构实验之链表九:双向链表
数据结构实验之链表九:双向链表 Time Limit: 1000 ms Memory Limit: 65536 KiB Problem Description 学会了单向链表,我们又多了一种解决问题的 ...
- The Top 50 Proprietary Programs that Drive You Crazy — and Their Open Source Alternatives
The Top 50 Proprietary Programs that Drive You Crazy — and Their Open Source Alternatives 01 / 22 / ...
- python selenium 测试配置信息(URL和浏览器)
config.ini # this is config file, only store browser type and server URL [browserType] #browserName ...
- phpstorm 中git 的使用
phpstorm 是一款不可多得的IDE 环境,它既是一款强大的编辑器,还是一款调试器,同时还是一款git 可视化管理工具哟,phpers 值得拥有.今天介绍的是他不为人知的强大功能 —— git. ...
- codeforces 1214
D 比赛的时候居然看漏了条件... 若在(x, y)格子,那么只能移动到(x+1, y)或(x, y+1) 这样的话就好做了,直接dp,然后统计每一种路径长度经过的点数. #include<cs ...
- mybatis 逆向工程(通过数据库表针对单表自动生成mybatis执行所需要的代码)
mybatis需要程序员自己编写sql语句,mybatis官方提供逆向工程,可以针对单表自动生成mybatis执行所需要的代码(mapper.java.mapper.xml.pojo…),可以让程序员 ...
- 简单的Spring Batch示例
使用Spring Batch做为批处理框架,可以完成常规的数据量不是特别大的离线计算. 现在写一个简单的入门版示例. 这里默认大家已经掌握了Spring Batch的基本知识,示例只是为了快速上手实践 ...
- H3C 在网络中的正确位置配置ACL包过滤