zoukankan      html  css  js  c++  java
  • $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
    ",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;
    }
    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
    ",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
    ",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
    ",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
    ",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;
    }
    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
    ",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
    ",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;
    }
    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
    ",l);
        return 0;
    }
    View Code
  • 相关阅读:
    SQL分页存储过程——表名、返回的列、排序字段、排序类型、条件、页尺寸、页码
    SQL——触发器——插入触发器——边学边项目写的。
    SQL链表查询 数据库为空
    【错误积累】更新失败,数据包解压时出现错误!
    VS使用技巧(转)
    命令模式
    代理模式
    模板方法模式
    享元模式
    MongoDB 分片2
  • 原文地址:https://www.cnblogs.com/lqsukida/p/11803780.html
Copyright © 2011-2022 走看看