zoukankan      html  css  js  c++  java
  • [考试反思]0115省选模拟8:等待

    不好。但凑和。

    再也不相信对拍了(然而肯定还是要写的)

    T1又是一个根号算法(当然可以更优),没想到,写了一个剪枝暴力,本来从复杂度上来说应该有80分,但是因为没有发现

    「加0不算对一个数进行修改」

    一个细节没注意,挂了45分。

    还写对拍了,但是暴力也没有注意这个细节,于是二者愉快的拍上了。。。

    T3的话写了个迷之网络流,感觉不太对于是愉快的写了一个状压。

    话说这辈子第一次靠自己不抄代码把$tarjan$写对,开心。(我为啥没联赛退役?因为它没考啊)

    又愉快的拍上了二十万组。于是自信的交了网络流。

    结果网络流20分,状压50分。。。

    就这些弱智玩意送了小一百分。。。能混到这个rank就靠一个T2

    然而T2是我三道题里花时间最少的,也没写对拍,反而得分最多。。。

    运气好,爱用STL,在别人开数组的地方开了一个$unoredred map$。数据微锅的情况下没有$RE$。靠非实力因素多拿了$13$分。

    所以其实rank应该再掉两个。。。

    考得还是挺烂的,但是这次除了没认真注意细节以外貌似是尽力了。。。

    所以我也做不出什么评价。只能继续加油吧。。。

    T1:序列

    题意:维护序列支持区间加,区间取$max$,询问单点值及从开始到现在为止的变化次数。$n,mle 100000$

    内存限制$32MB$。时间限制$1000ms$

    线段树,假装小清新,维护最大值与最小值并注意+0不算改变后可以拿到80分。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define S 400002
     4 #define ll long long
     5 #define lc p<<1
     6 #define rc p<<1|1
     7 #define md (cl+cr>>1)
     8 ll lz[S],mn[S],mx[S];int n,a[S],m,tms[S];char s[9];
     9 void up(int p){mn[p]=min(mn[lc],mn[rc]);mx[p]=max(mx[lc],mx[rc]);}
    10 void build(int p=1,int cl=1,int cr=n){
    11     if(cl==cr){mn[p]=mx[p]=a[cl];return;}
    12     build(lc,cl,md);build(rc,md+1,cr);up(p);
    13 }
    14 void down(int p){
    15     if(tms[p])tms[lc]+=tms[p],tms[rc]+=tms[p],tms[p]=0;
    16     if(mn[p]==mx[p])mn[lc]=mn[rc]=mx[lc]=mx[rc]=mn[p],lz[p]=0;
    17     else if(lz[p])mn[lc]+=lz[p],mn[rc]+=lz[p],mx[lc]+=lz[p],mx[rc]+=lz[p],lz[lc]+=lz[p],lz[rc]+=lz[p],lz[p]=0;
    18 }
    19 void Max(int l,int r,int w,int p=1,int cl=1,int cr=n){
    20     if(w<=mn[p])return;
    21     if(l<=cl&&cr<=r&&w>mx[p]){tms[p]++;lz[p]=0;mn[p]=mx[p]=w;return;}
    22     down(p);
    23     if(l<=md)Max(l,r,w,lc,cl,md);
    24     if(r>md)Max(l,r,w,rc,md+1,cr);
    25     up(p);
    26 }
    27 void add(int l,int r,int v,int p=1,int cl=1,int cr=n){
    28     if(v==0)return;
    29     if(l<=cl&&cr<=r){
    30         if(mn[p]==mx[p])mn[p]+=v,mx[p]+=v,lz[p]=0;
    31         else lz[p]+=v,mn[p]+=v,mx[p]+=v;
    32         tms[p]++;return;
    33     }
    34     down(p);
    35     if(l<=md)add(l,r,v,lc,cl,md);
    36     if(r>md)add(l,r,v,rc,md+1,cr);
    37     up(p);
    38 }
    39 int ask(int x,int p=1,int cl=1,int cr=n){
    40     if(cl==cr)return p;
    41     down(p);
    42     return x<=md?ask(x,lc,cl,md):ask(x,rc,md+1,cr);
    43 }
    44 int main(){//freopen("1.in","r",stdin);freopen("1.out","w",stdout);
    45     scanf("%d",&n);
    46     for(int i=1;i<=n;++i)scanf("%d",&a[i]);
    47     build();
    48     scanf("%d",&m);while(m-->0){
    49         scanf("%s",s);int a,b,c;
    50         if(s[0]=='A')scanf("%d%d%d",&a,&b,&c),add(a,b,c);
    51         if(s[0]=='M')scanf("%d%d%d",&a,&b,&c),Max(a,b,c);
    52         if(s[0]=='Q')scanf("%d",&a),a=ask(a),printf("%lld %d
    ",mn[a],tms[a]);
    53     }
    54 }
    View Code

    正解很多,能看懂的就一个分块。块内部排序,维护加法标记和「已经进行过的取max中的最大值」两个标记。

    有序之后,变化次数的累加可以差分,而且如果整个块都被操作的话单调性不变。

    然后T的还不如线段树。把块长开成36之后它AC了???36是个什么块啊?????

    理论复杂度$O(nsqrt{n} log n)$。然而我常数写太丑了。。。卡过去的

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define S 400002
     4 #define ll long long
     5 ll lz[S],mx[S];int bc,n,m,tms[S],cl[S],cr[S],bl[S],B,lzt[S],pt[S];char s[9];
     6 struct data{long long v;int p;}da[S];
     7 bool cv(data x,data y){return x.v<y.v;}
     8 bool cp(data x,data y){return x.p<y.p;}
     9 void down(int x){
    10     for(int i=cr[x]-1;i>=cl[x];--i)lzt[i]+=lzt[i+1];
    11     for(int i=cl[x];i<=cr[x];++i)tms[da[i].p]+=lzt[i],lzt[i]=0;
    12     for(int i=cl[x];i<=cr[x];++i)da[i].v+=lz[x];
    13     for(int i=cl[x];i<=cr[x];++i)if(da[i].v<mx[x])da[i].v=mx[x];
    14     lz[x]=0;mx[x]=-123456789012345;pt[x]=cl[x];
    15     sort(da+cl[x],da+cr[x]+1,cp);
    16 }
    17 void up(int x){sort(da+cl[x],da+cr[x]+1,cv);}
    18 int main(){//freopen("1.in","r",stdin);freopen("1.out","w",stdout);
    19     scanf("%d",&n);
    20     for(int i=1;i<=n;++i)scanf("%lld",&da[i].v),da[i].p=i;
    21     B=36;bc=n/B;
    22     for(int i=1;i<=bc;++i)cl[i]=i*B-B+1,cr[i]=i*B;
    23     if(cr[bc]!=n)cr[++bc]=n,cl[bc]=cr[bc-1]+1;
    24     for(int i=1;i<=bc;++i)for(int j=cl[i];j<=cr[i];++j)bl[j]=i;
    25     for(int i=1;i<=bc;++i)up(i),mx[i]=-123456789012345,pt[i]=cl[i];
    26     scanf("%d",&m);while(m-->0){
    27         scanf("%s",s);int a,b,c;
    28         if(s[0]=='A'){
    29             scanf("%d%d%d",&a,&b,&c);
    30             if(c==0)continue;
    31             if(bl[a]==bl[b]){down(bl[a]);for(int i=a;i<=b;++i)da[i].v+=c,tms[i]++;up(bl[a]);}
    32             else{
    33                 down(bl[a]);for(int i=a;i<=cr[bl[a]];++i)da[i].v+=c,tms[i]++;up(bl[a]);
    34                 down(bl[b]);for(int i=cl[bl[b]];i<=b;++i)da[i].v+=c,tms[i]++;up(bl[b]);
    35                 for(int i=bl[a]+1;i<bl[b];++i)lz[i]+=c,mx[i]+=c,lzt[cr[i]]++;
    36             }
    37         }
    38         if(s[0]=='M'){
    39             scanf("%d%d%d",&a,&b,&c);
    40             if(bl[a]==bl[b]){down(bl[a]);for(int i=a;i<=b;++i)if(da[i].v<c)da[i].v=c,tms[i]++;up(bl[a]);}
    41             else{
    42                 down(bl[a]);for(int i=a;i<=cr[bl[a]];++i)if(da[i].v<c)da[i].v=c,tms[i]++;up(bl[a]);
    43                 down(bl[b]);for(int i=cl[bl[b]];i<=b;++i)if(da[i].v<c)da[i].v=c,tms[i]++;up(bl[b]);
    44                 for(int i=bl[a]+1;i<bl[b];++i){
    45                     if(c<=mx[i])continue;
    46                     while(pt[i]<cr[i]&&lz[i]+da[pt[i]+1].v<c)pt[i]++;
    47                     if(lz[i]+da[pt[i]].v>=c)continue;
    48                     lzt[pt[i]]++;mx[i]=c;
    49                 }
    50             }
    51         }
    52         if(s[0]=='Q')scanf("%d",&a),down(bl[a]),printf("%lld %d
    ",da[a].v,tms[a]),up(bl[a]);
    53     }
    54 }
    View Code

    T2:旅行计划

    题意:无向图多次询问两点之间在模意义下的最短路(询问间模数可能不同)$n,m,q le 10^5$

    子任务:$k$为奇数/$k=2,w=1$

    其实这两档部分分给的挺好的,但是想到正解仍然不容易。

    k为奇数时你可以在同一条边来回走直到刷出你想要的数,所以只要联通答案就是$0$

    对于后者,奇偶染色判奇环,如果联通块内存在奇环一定可以刷出想要的余数,否则就看两个点颜色是否相同。

    对于其它子任务,因为要取模和环的问题所以考场上我想到了要gcd,然后就想不下去了。

    事实上我们预处理把每个联通块里的边都除以边权的gcd再奇偶染色。

    询问时,如果模数中2的指数少于边的gcd中的2的指数,那么余数一定是0。

    否则如果k是奇数也可以刷出想要的数。

    否则如果有奇环也一定能刷出来。

    再否则如果染色相同那么也就不用刷了最短路模完就是0了。

    再否则,我们也可以通过刷边的方法,将答案最小化为$gcd(k,gcd(edge))$

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define S 200005
     4 int n,m,q,fir[S],l[S],to[S],v[S],bl[S],co[S],y[S],tim,g,ans,k,ec,eg[S];
     5 void link(int a,int b,int c){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;v[ec]=c;}
     6 void paint(int p,int c){
     7     bl[p]=tim;co[p]=c;
     8     for(int i=fir[p];i;i=l[i])if(!co[to[i]])paint(to[i],(co[p]+v[i]&1)+2);
     9         else if((co[p]+v[i]&1)+2!=co[to[i]])y[tim]=1;
    10 }
    11 int gcd(int a,int b){return b?gcd(b,a%b):a;}
    12 int main(){
    13     scanf("%d%d%d",&n,&m,&q);
    14     for(int i=1,a,b,c;i<=m;++i)scanf("%d%d%d",&a,&b,&c),link(a,b,c),link(b,a,c);
    15     for(int i=1;i<=n;++i)if(!co[i])tim++,paint(i,2);
    16     for(int i=1;i<=n;++i)for(int j=fir[i];j;j=l[j])eg[bl[i]]=gcd(eg[bl[i]],v[j]);
    17     for(int i=1;i<=tim;++i)y[i]=0;
    18     for(int i=1;i<=n;++i)for(int j=fir[i];j;j=l[j])v[j]/=eg[bl[i]];
    19     for(int i=1;i<=n;++i)co[i]=0;tim=0;
    20     for(int i=1;i<=n;++i)if(!co[i])tim++,paint(i,2);
    21     while(q-->0){
    22         int x;scanf("%d%d%d",&x,&g,&k);
    23         if(bl[x]!=bl[g])puts("NIE");
    24         else printf("%d
    ",eg[bl[x]]/gcd(k,eg[bl[x]])%2==0||k&1||y[bl[x]]||co[x]==co[g]?0:gcd(k,eg[bl[x]]));
    25     }
    26 }
    View Code

    T3:Hack

    题意:有向联通图,选定边集使所有1到n的路径均经过边集中的边合计恰好一次,最小化边权和。$nle100,m le 2500$

    模型很像最小割。但是最小割并没有保证恰好经过一次。

    经过多于一次的方案就是走某些路径由最小割后$T$点集走回了$S$点集。

    于是我们把反向边开成$inf$就好了。这样就保证了即使它可以往回走的路径也被割断。

    然而没必要$tarjan$缩点。直接按照含义跑,最后最小割是0表示不联通,无解。最小割$inf$表示都至少经过两次,也无解。

    判掉之后你的网络流图上反向边$inf$成环所以你一定不割环上边所以是对的。$miku$大神实测可以$AC$

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define S 1234567
     4 int fir[S],l[S],to[S],ec,v[S],dfn[S],low[S],tim,in[S],s[S],tp,bl[S],scc,n,m;
     5 void link(int a,int b,int w){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;v[ec]=w;}
     6 void tarjan(int p){
     7     dfn[p]=low[p]=++tim;s[++tp]=p;in[p]=1;
     8     for(int i=fir[p];i;i=l[i])if(!dfn[to[i]])tarjan(to[i]),low[p]=min(low[p],low[to[i]]);
     9         else if(in[to[i]])low[p]=min(low[p],dfn[to[i]]);
    10     if(dfn[p]==low[p]){++scc;while(in[p])in[s[tp]]=0,bl[s[tp]]=scc,tp--;}
    11 }
    12 int Fir[S],L[S],To[S],q[S],Ec=1,al[S],d[S];long long ans,V[S];
    13 void Link(int a,int b,int w){
    14     L[++Ec]=Fir[a];Fir[a]=Ec;To[Ec]=b;V[Ec]=w;
    15     L[++Ec]=Fir[b];Fir[b]=Ec;To[Ec]=a;V[Ec]=123456789012345;
    16 }
    17 bool SPFA(){
    18     for(int i=1;i<=scc;++i)d[i]=123456789;d[bl[1]]=0;q[1]=bl[1];
    19     for(int h=1,t=1;h<=t;++h)for(int i=Fir[q[h]];i;i=L[i])if(V[i]&&d[q[h]]+1<d[To[i]])
    20         d[q[++t]=To[i]]=d[q[h]]+1;
    21     return d[bl[n]]!=123456789;
    22 }
    23 long long dinic(int p,long long flow){//cout<<p<<' '<<flow<<endl;
    24     long long r=flow;
    25     if(p==bl[n])return flow;
    26     for(int i=Fir[p];i&&r;i=L[i])if(d[To[i]]==d[p]+1&&V[i]){
    27         long long x=dinic(To[i],min(r,V[i]));
    28         if(!x)d[To[i]]=-1;
    29         V[i]-=x;V[i^1]+=x;r-=x;
    30     }return flow-r;
    31 }
    32 int main(){//freopen("3.in","r",stdin);freopen("3.out","w",stdout);
    33     scanf("%d%d",&n,&m);
    34     for(int i=1,a,b,w;i<=m;++i)scanf("%d%d%d",&a,&b,&w),link(a+1,b+1,w);
    35     tarjan(1);
    36     if(bl[1]==bl[n]||!bl[n])return puts("-1"),0;
    37     for(int i=1;i<=n;++i)for(int j=fir[i];j;j=l[j])if(bl[i]&&bl[to[j]]&&bl[to[j]]!=bl[i])Link(bl[i],bl[to[j]],v[j]);
    38     while(SPFA())ans+=dinic(bl[1],123456789012345);
    39     printf("%lld
    ",ans);
    40 }
    View Code

    .

  • 相关阅读:
    Codeforces 876C Classroom Watch:枚举
    Codeforces 876B Divisiblity of Differences:数学【任意两数之差为k的倍数】
    BZOJ 3943 [Usaco2015 Feb]SuperBull:最大生成树
    BZOJ 3391 [Usaco2004 Dec]Tree Cutting网络破坏:dfs【无根树 节点分枝子树大小】
    markdown常用数学符号小结
    BZOJ3211花神游历各国-线段树&树状数组-(HDU4027同类型)
    一维二维树状数组写法总结
    hdu4352-XHXJ's LIS状压DP+数位DP
    常用Git命令以及出现的状况ing
    bitset简单用法
  • 原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/12198374.html
Copyright © 2011-2022 走看看