zoukankan      html  css  js  c++  java
  • [考试反思]1006csp-s模拟测试62:隔断

    本来说好的好一场烂一场。

    那样的日子结束了,连着烂了两场。。。
    幸亏T3傻逼了救我一命不算太惨。。。

    T1树上的特殊性质会做但是没有继续想下去就死在错贪心上了还没有过那个点。。。

    T2迭代至稳定被我错误的hack了,贪心炸了。

    T3我觉得考场上我在yy证明,但是它是对的。

    于是我去了趟厕所清醒了一下,回来还是hack不掉我的证明。。。

    于是去隔壁问教练w的范围,不告诉。。。

    那我要打高精???

    不可能的我又不是正解,于是开个long long就交了。

    然后竟然就A了???

    据说开int会飞天。

    T1:Graph

    尽量多的边配对。。。

    树上的就可以简单贪心。

    但是变成图之后多了些横叉边,然而并没有什么影响。

    照样配对就可以了,特殊处理一下树边。

    对于问题性质的扩展能力还是有所欠缺啊。。。

     1 #include<cstdio>
     2 #include<vector>
     3 using namespace std;
     4 int n,m,ec=1,fir[100005],al[100005],l[400005],to[400005],alt;
     5 int ansx[200005],ansp[200005],ansy[200005];
     6 void link(int a,int b){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;}
     7 int dfs(int p,int fa){//printf("->%d %d
    ",p,fa);
     8     al[p]=1;int lst=0;
     9     for(int i=fir[p];i;i=l[i])if(!al[to[i]]){
    10         if(!dfs(to[i],p))continue;
    11         if(lst)++alt,ansx[alt]=lst,ansp[alt]=p,ansy[alt]=to[i],lst=0;
    12         else lst=to[i];
    13     }else if(al[to[i]]&&to[i]!=fa&&to[i]>p)
    14         if(lst)++alt,ansx[alt]=lst,ansp[alt]=p,ansy[alt]=to[i],lst=0;
    15         else lst=to[i];
    16     if(fa&&lst){++alt,ansx[alt]=lst,ansp[alt]=p,ansy[alt]=fa,lst=0;return 0;}
    17     return 1;
    18 }
    19 int main(){
    20     scanf("%d%d",&n,&m);
    21     for(int x,y,i=1;i<=m;++i) scanf("%d%d",&x,&y),link(x,y),link(y,x);
    22     for(int i=1;i<=n;++i) if(!al[i]) dfs(i,0);
    23     printf("%d
    ",alt);
    24     for(int i=1;i<=alt;++i)printf("%d %d %d
    ",ansx[i],ansp[i],ansy[i]);
    25 }
    View Code

    思路积累:

    • 性质由树向图上扩展
    • 贪心:正确性证明

    T2:Permutation/Wide Swap

    类似于《菜肴制作》,用到了它的结论:

    正向字典序最小,等同于下标与数值互换后的数组的逆向字典序最大。(逆向就是指reverse一下)

    所以现在问题变成了构造最大的下标与数值互换的数组(叫pos吧)的逆向字典序最大。

    注意下面这个结论并不是恒成立的(尽管据说本题成立但是没有被证明):

    正向字典序最大等同于原数组逆向字典序最小

    现在考虑如何构造吧。

    忘掉原数组,现在我们的任务就是构造pos。

    现在的互换规则就是相邻两位的差至少为k。

    那么因为是相邻位交换,所以如果两个数差不足k那么它们永远不能互相跨越即交换相对位置。

    那么对于所有i<j,posi与posj的差的绝对值小于k时就建上边表示不能跨越。

    那么就可以得到一个DAG了,跑一遍拓扑就可以得到合法的构造方案。

    但是边太多了考虑优化。

    因为每个数支配的都是一段连续的区间,所以有些区间存在间接支配关系。

    倒序考虑pos串,找到下标在合法区间内下标最相近的点建边即可。

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<queue>
     4 using namespace std;
     5 priority_queue<int>q;
     6 int a[500005],b[500005],cl[2000005],cr[2000005],mn[2000005],n,k;
     7 int fir[500005],l[1000005],to[1000005],cnt,deg[500005];
     8 void link(int a,int b){l[++cnt]=fir[a];fir[a]=cnt;to[cnt]=b;deg[b]++;}
     9 void build(int p,int l,int r){
    10     cl[p]=l;cr[p]=r;mn[p]=1234567;
    11     if(l==r)return;
    12     build(p<<1,l,l+r>>1);build(p<<1|1,(l+r>>1)+1,r);
    13 }
    14 void set(int p,int pos,int w){
    15     if(cl[p]==cr[p]){mn[p]=w;return;}
    16     if(pos<=cr[p<<1])set(p<<1,pos,w);
    17     else set(p<<1|1,pos,w);
    18     mn[p]=min(mn[p<<1],mn[p<<1|1]);
    19 }
    20 int ask(int p,int l,int r){if(l>r)return 1234567;
    21     if(l<=cl[p]&&cr[p]<=r)return mn[p];
    22     return min(l<=cr[p<<1]?ask(p<<1,l,r):1234567,r>=cl[p<<1|1]?ask(p<<1|1,l,r):1234567);
    23 }
    24 int main(){
    25     scanf("%d%d",&n,&k);build(1,1,n);
    26     for(int i=1;i<=n;++i)scanf("%d",&a[i]),b[a[i]]=i;//for(int i=1;i<=n;++i)printf("%d ",b[i]);puts("");
    27     for(int i=n;i;--i){
    28         int l=ask(1,max(b[i]-k+1,1),b[i]-1),r=ask(1,b[i]+1,max(n,b[i]-k+1));
    29         if(l<1234567)link(b[l],b[i]);if(r<1234567)link(b[r],b[i]);
    30         set(1,b[i],i);
    31     }
    32     for(int i=n;i;--i)if(!deg[i])q.push(i);int aln=n;
    33     while(!q.empty()){
    34         int x=q.top();q.pop();b[aln--]=x;//printf("topu:%d
    ",x);
    35         for(int i=fir[x];i;i=l[i]){deg[to[i]]--;if(!deg[to[i]])q.push(to[i]);}
    36     }//for(int i=1;i<=n;++i)printf("%d ",b[i]);puts("");
    37     for(int i=1;i<=n;++i)a[b[i]]=i;
    38     for(int i=1;i<=n;++i)printf("%d
    ",a[i]);
    39 }
    View Code

    思路积累:

    • 用拓扑排序解决限制类问题
    • 问题转化
    • 字典序的结论

    T3:Tree

    好题。虽说做法很蠢——输出所有边权和。

    你只要考虑并查集从大到小解锁每一条边就可以得到一个合法的最优排列。

    1 #include<cstdio>
    2 int n;long long tot,w;
    3 int main(){
    4     scanf("%d",&n);
    5     for(int x,y,i=1;i<n;++i)scanf("%d%d%lld",&x,&y,&w),tot+=w;
    6     printf("%lld
    ",tot);
    7 }
    View Code
  • 相关阅读:
    写给Web开发人员看的Nginx介绍
    Nginx安装及配置详解
    Intellij IDEA 热部署处理
    JSP自定义标签就是如此简单
    过滤器入门看这一篇就够了
    Caffe FCN:可视化featureMaps和Weights(C++)、获取FCN结果
    Caffe RPN :error C2220: warning treated as error
    实例分割:MaskXRCnn 与Visual Genome数据集
    Detectron-MaskRCnn: 用于抠图的FCNN
    CaffeMFC:caffe.pb.h(2525): error C2059: syntax error : 'constant'
  • 原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/11631355.html
Copyright © 2011-2022 走看看