$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;
}
View Code

$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;}
View Code

$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;
}
View Code

$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;
}
View Code

$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;
}
View Code

$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;
}
View Code

$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;
}
View Code

$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;
}
View Code

$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+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\n",as);return 0;}
View Code

 

$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;
}
View Code

$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;
}
View Code


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM