照例先放个链接$QwQ$
$A$
$QwQ$之前写过题解辣.
重新说下趴,就给横坐标纵坐标也开点,然后每个点连向对应横纵坐标边权为$0$,相邻横坐标点之间连边,相邻纵坐标点之间连边,跑个最短路就完事$QwQ$
还有一种想法是先按$x$排序相邻相连,再按$y$排序相邻相连.因为两个不相邻的一定能通过两个相邻达到,所以是对的.
$upd:$
我是真的自闭,,,之前做这题的时候$bzoj$在维护,我就在$darkbzoj$上交,过了.
然后今天在$bzoj$上交,不是$TLE$就是$MLE$,就很自闭.
调了很久之后发现是数组开大了:)
$wzbl$
View Code#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 ",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 ",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 ",dis[T]); return 0; }
$B$
题目大意可以上洛谷康康.注意下是有向边就成$/kel$
考虑到一个强联通分量内肯定全部可以拿走,所以跑个$tarjan$缩点,就成了一个$DAG$.
然后随便$dp$一下就完事,$QwQ$
View Code#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 ",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$
View Code#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$
View Code#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 ",as); } return 0; }
$E$
,,,我感觉这题我见过七八遍了.
不想说了$QAQ$
View Code#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$很久很久之前就做过辣.
View Code#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$
View Code#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 ",as); return 0; }
$H$
不难想到肯定优先用数量多的之间配对?
用堆维护下数量就完事.$QwQ$
$QwQQQQQ$注意一个细节,就一定是每次取出来之后只拿一个,不能把第三大的全拿完了$QwQ$
View Code#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 ",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 ",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$
View Code#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+10; int n,m,a[N],fac[20],as; bool chck(int len){for(int i=1;i<=m;i+=(len<<1))if((a[i]+len)^(a[i+len]))return 0;return 1;} void swp(int x,int y,int l){rp(i,0,l-1)swap(a[x+i],a[y+i]);} void dfs(int len,int cnt) { if(len^1 && !chck(len>>1))return;;if(!(len^m)){as+=fac[cnt];return;} dfs(len<<1,cnt);int p[10],gdgs=0; for(int i=1;i<=m;i+=(len<<1))if((a[i]+len)^a[i+len]){if(!(gdgs^4))return;else p[++gdgs]=i,p[++gdgs]=i+len;} rp(i,1,gdgs)rp(j,i+1,gdgs)swp(p[i],p[j],len),dfs(len<<1,cnt+1),swp(p[i],p[j],len); } signed main(){scanf("%lld",&n);m=1<<n;rp(i,1,m)scanf("%lld",&a[i]);fac[0]=1;rp(i,1,n)fac[i]=fac[i-1]*i;dfs(1,0);printf("%lld ",as);return 0;}
$J$
听$lyh$说要$A*$?我头铁写了发搜索过了$QwQ$
View Code#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 ",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 ",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 ",as);} return 0; }
$K$
题目大意说给定一个图,每条边有边权,有$K$条边可以把边权变为$0$.问$S$到$T$的路径上最大边权的最小值是多少.
$umm$这个不是一看就二分嘛?考虑二分这个权值$mid$.然后长度大于$mid$的边权设为$1$,小于等于$mid$的设为$0$.跑个最短路就完事.
View Code#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 ",l); return 0; }