zoukankan      html  css  js  c++  java
  • gym101908 [2018-2019 ACM-ICPC Brazil Subregional Programming Contest] 题解

    感觉难度和邀请赛类似,题目质量也低于国内邀请赛,(题面/数据不出锅的情况下)

    https://codeforces.com/gym/101908


    A.大概是莫比乌斯之类的,不会


    B:博弈,不会


    C:欧拉公式+二维偏序

    首先,根据平面图欧拉公式,可推导出答案为$n+m+1+$交叉的数量

    交叉的数量由三部分构成,横竖交叉数,横横交叉数和竖竖交叉数

    显然,前者为$nm$,后两个为简单的二维偏序问题,

    比较扯淡的是,先T了一发,从map改完二分,交的时候才意识到是没关同步

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(ii,a,b) for(int ii=a;ii<=b;++ii)
    #define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
    #define fi first
    #define se second
    #define pii pair<int,int>
    #define all(x) x.begin(),x.end()
    using namespace std;//head
    const int maxn=1e6+10,maxm=2e6+10;
    const ll INF=0x3f3f3f3f,mod=1e9+7;
    int casn,n,m,k;
    ll x,y;
    class bit{public:
    	int node[maxn];
    	inline int lb(int x) {return x&(-x);}
    	void init(int n){fill_n(node,n+1,0);}
      inline void update(int pos,int val,int n){for(;pos>0&&pos<=n;pos+=lb(pos)) node[pos]+=val;}
      inline int ask(int pos,int sum,int n){for(;pos>0;pos-=lb(pos)) sum+=node[pos];return sum;}
      inline int query(int l,int r,int n){return ask(r,0,n)-ask(l-1,0,n);}
    }tree;
    int px[maxn];
    ll solve(int n){
      int cntx=0;
      vector<pii>h;
      rep(i,1,n){
        int a,b;cin>>a>>b;
        h.emplace_back(a,b);
        px[++cntx]=b;
      }
      sort(px+1,px+1+cntx);
      cntx=unique(px+1,px+1+cntx)-px-1;
      for(auto &i:h){
        i.se=lower_bound(px+1,px+1+cntx,i.se)-px;
      }
      ll cnt=0;
      sort(all(h));
      tree.init(cntx);
      for(auto &i:h){
        cnt+=tree.query(i.se+1,cntx,cntx);
        tree.update(i.se,1,cntx);
      }
      return cnt;
    }
    int main() {IO;
      cin>>x>>y>>n>>m;
      ll ans=solve(n)+solve(m)+n+m+1+1ll*n*m;
      cout<<ans<<endl;
    }
    

    D题:签到


    E题:签到(30ms跑1e8已经是cf的基本操作了吗?)


    F题:状压DP

    先对于节目,按结束时间排序,然后依次枚举:节目数量,节目,选择的$Festival$状态,

    复杂度$(2^n)(sum{M_i})^2$,大概是1e9,最后运行时间500ms,只能说CF评测机牛逼了

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn = 86500;
    int dp[1100][1<<10];
    struct node {int st, et, val, id;}p[1100]; 
    bool cmp(node x, node y) {return x.et < y.et;}
    int main() {
      std::ios::sync_with_stdio(false);
      int n,cnt = 0, ma = 0,ans = -1;
      cin >> n;
      for(int i = 0; i < n; i++) {
        int k;cin >> k;
        for(int j = 0; j < k; j++) {
          int a, b, c, d;
          cin >> a >> b >> c;  d = i;
          p[++cnt] = {a, b, c, d};
          ma = max(ma, b);
        }
      }
      sort(p+1, p+1+cnt, cmp);
      memset(dp, -1, sizeof dp);
      dp[0][0] = 0;
      for(int i = 1; i <= cnt; i++) {
        dp[i][0] = 0;
        for(int j = 0; j < i; j++) {
          if(p[i].st < p[j].et)  continue;
          for(int k = 1; k < (1<<n); k++) {
            if((k&(1<<p[i].id))) {
              if(dp[j][k] != -1)  dp[i][k] = max(dp[i][k], dp[j][k]+p[i].val);
              if(dp[j][k-(1<<p[i].id)] != -1)  dp[i][k] = max(dp[i][k], dp[j][k-(1<<p[i].id)]+p[i].val);
            }
          }
        }
        ans = max(ans, dp[i][(1<<n)-1]);
      }
      cout << ans << "
    ";
    }
    

     经过研究,可以优化为$(2^n)sum{M_i}$,实测31ms

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn = 86500;
    int dp[1100][1<<10], ma[1100][1<<10],n, cnt;
    struct node {int st, et, val, id;}p[1100];
    bool cmp(node x, node y) {return x.et < y.et;}
    int f(int R, int k) {
      int ans = 0, l = 1, r = R-1;
      while(l <= r) {
        int mid = (l+r)>>1;
        if(p[mid].et <= k)  ans = mid, l = mid+1;
        else r = mid-1;
      }
      return ans;
    }
    int main() {
      std::ios::sync_with_stdio(false);
      cin >> n;
      for(int i = 0; i < n; i++) {
        int k;cin >> k;
        for(int j = 0; j < k; j++) {
          int a, b, c, d;
          cin >> a >> b >> c;  d = i;
          p[++cnt] = {a, b, c, d};
        }
      }
      sort(p+1, p+1+cnt, cmp);
      memset(dp, -1, sizeof dp);
      memset(ma, -1, sizeof ma);
      ma[0][0] = dp[0][0] = 0;
      int ans = -1;
      for(int i = 1; i <= cnt; i++) {
        dp[i][0] = 0;
        int sign = f(i, p[i].st);
        for(int k = 1; k < (1<<n); k++) {
          if(!(k&(1<<p[i].id)))  continue;
          if(ma[sign][k] != -1)  dp[i][k] = max(dp[i][k], ma[sign][k]+p[i].val);
          if(ma[sign][k-(1<<p[i].id)] != -1)  dp[i][k] = max(dp[i][k], ma[sign][k-(1<<p[i].id)]+p[i].val);
        }
        for(int k = 0; k < (1<<n); k++) ma[i][k] = max(ma[i-1][k], dp[i][k]);
      }
      cout << ma[cnt][(1<<n)-1] << "
    ";
      return 0;
    }
    

    G:二分+最小割

    裸题,显然答案为使用过的最大的边,那么二分答案,看最小割是否等于$sum{D_i}$即可,数组开小RE了一发

    #include<bits/stdc++.h>
    #define rep(ii,a,b) for(int ii=a;ii<=b;++ii)
    #define per(ii,a,b) for(int ii=b;ii>=a;--ii)
    #define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
    using namespace std;//head
    const int maxn=1e5+10,maxm=2e6+10;
    const int INF=0x3f3f3f3f,mod=1e9+7;
    int casn,n,m,k,root;
    class mxf{public:
      struct node{int to,next;int cap;}e[maxm<<1];
      int cur[maxn],head[maxn],que[maxn],dis[maxn],nume=1,s,t;
      inline void adde(int a,int b,int c){e[++nume]={b,head[a],c};head[a]=nume;}
      inline void add(int a,int b,int c){adde(a,b,c);adde(b,a,0);}
      void init(int n=maxn-1){memset(head,0,(n+1)<<2);nume=1;}
      bool bfs(){
      memset(dis,-1,(t+1)<<2);
        dis[t]=0,que[0]=t;
        int tp=0,ed=1;
        while(tp!=ed){
          int now=que[tp++];tp%=maxn;
          for(int i=head[now];i;i=e[i].next){
          int to=e[i].to;
          if(dis[to]==-1&&e[i^1].cap){
            dis[to]=dis[now]+1;
            if(to==s) return true;
            que[ed++]=to;ed%=maxn;
          }
          }
        }
        return false;
      }
      int dfs(int now,int flow=0x3f3f3f3f){
        if(now==t||flow==0) return flow;
        int use=0;
        for(int &i=head[now];i&&use!=flow;i=e[i].next){
          int to=e[i].to;
          if(dis[to]+1!=dis[now])continue;
          int tmp=dfs(to,min(e[i].cap,flow-use));
          e[i].cap-=tmp,e[i^1].cap+=tmp,use+=tmp;
        }
        if(!use) dis[now]=-1;
        return use;
      }
      int getflow(int ss,int tt){
        s=ss,t=tt;int ans=0;
        memcpy(cur,head,(t+1)<<2);
        while(bfs()){
          ans+=dfs(s);
          memcpy(head,cur,(t+1)<<2);
        }
        return ans;
      }
    }net;
    int need[maxn],have[maxn];
    int sum,a[maxn],b[maxn],c[maxn];
    bool check(int mid){
      net.init(n+m+10);
      int ss=n+m+1,tt=ss+1;
      rep(i,1,k)if(c[i]<=mid)net.add(a[i]+n,b[i],INF);
      rep(i,1,n)net.add(i,tt,need[i]);
      rep(i,1,m)net.add(ss,i+n,have[i]);
      return net.getflow(ss,tt)>=sum;
    }
    int main() {IO;
      cin>>n>>m>>k;
      rep(i,1,n)(cin>>need[i]),sum+=need[i];
      rep(i,1,m)cin>>have[i];
      rep(i,1,k)cin>>b[i]>>a[i]>>c[i];
      int l=1,r=1e6;
      int ans=-1;
      while(l<=r){
        int mid=(l+r)>>1;
        if(check(mid)) ans=mid,r=mid-1;
        else l=mid+1;
      }
      cout<<ans<<endl;
    }
    

    H题:没看


    I题:签到


    J题:没看


    I题:计算几何,不会


    L题:树上链交裸题

    一种做法是用树链剖分,单次查询是$log^2n$,很裸也很简单

    但是这次我尝试写了单次$logn$直接讨论情况的做法,由于本题$Q$很小,拉不开差距,

    具体情况大概分为3类,讨论了很多发才过

    #include<bits/stdc++.h>
    #define rep(ii,a,b) for(int ii=a;ii<=b;++ii)
    #define forn(i,x) for(int i=head[x];i;i=e[i].next)
    #define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
    using namespace std;//head
    const int maxn=2e5+10,maxm=2e6+10;
    int casn,n,m,k,root;
    class graph{public:
      struct node{int to,next;}e[maxn<<1];
      int head[maxn],nume,dfn[maxn];
      inline void add(int a,int b){
        e[++nume]={b,head[a]};
        head[a]=nume;
      }
      int ltop[maxn],fa[maxn],deep[maxn];
      int sz[maxn],remp[maxn];
      int son[maxn],cnt;
      void init(int n){rep(i,1,n) head[i]=0;cnt=0,nume=1;}
      void dfs1(int now=root,int pre=root,int d=0){
        deep[now]=d,fa[now]=pre,sz[now]=1,son[now]=0;
        forn(i,now){
          int to=e[i].to;
          if(to!=pre) {
            dfs1(to,now,d+1);
            sz[now]+=sz[to];
            if(sz[to]>sz[son[now]]) son[now]=to;
          }
        }
      }
      void dfs2(int now=root,int pre=root,int sp=root){
        ltop[now]=sp;dfn[now]=++cnt;remp[cnt]=now;
          if(son[now])  dfs2(son[now],now,sp);
          forn(i,now){
            int to=e[i].to;
            if(to!=son[now]&&to!=pre) dfs2(to,now,to);
          }
      }
      void getchain(){dfs1();dfs2();}
      int lca(int x,int y){
        for(;ltop[x]!=ltop[y];deep[ltop[x]]>deep[ltop[y]]?x=fa[ltop[x]]:y=fa[ltop[y]]);
        return deep[x]<deep[y]?x:y;
      }
      inline int getdis(int a,int b){return deep[a]+deep[b]-2*deep[lca(a,b)];}
      bool check(int a,int b){return dfn[a]<=dfn[b]&&dfn[a]+sz[a]-1>=dfn[b]+sz[b]-1;}
      int getans(int a1,int a2,int b1,int b2){
        int ra=lca(a1,a2);
        bool f1=check(ra,b1),f2=check(ra,b2);
        if(!f1&&!f2) return 0;
        if(f1&&f2){
          int rb=lca(b1,b2);
          if(!( check(rb,a1)||check(rb,a2)))return 0;
          int r1=lca(a1,b1),r2=lca(a1,b2),r3=lca(a2,b1),r4=lca(a2,b2);
          if(r1==r3&&r2==r4) return 1;
          return getdis(r1==ra?r3:r1,r2==ra?r4:r2)+1;
        }
        if(!f1)swap(b1,b2);
        int r1=lca(a1,b1),r3=lca(a2,b1);
        return getdis(r1==ra?r3:r1,ra)+1;
      }
    }g;
    int d[maxn],a,b,a1,a2,b1,b2;
    int main() {IO;
      cin>>n>>m;
      rep(i,2,n){
        cin>>a>>b;
        g.add(a,b);g.add(b,a);
        d[a]++,d[b]++;
      }
      rep(i,1,n) if(d[i]>1) {root=i;break;}
      g.getchain();
      while(m--){
        cin>>a1>>a2>>b1>>b2;
        int ans=g.getans(a1,a2,b1,b2);
        cout<<ans<<endl;
      }
    }
    

    M题:没看


  • 相关阅读:
    Tenserflow学习日记(13)
    Tenserflow学习日记(12)
    Tenserflow学习日记(10)
    利用file_get_contents();抓取网络上需要的信息
    laravel5.4自定义验证规则
    getimagesize();获取图片的长度与宽度
    php得到程序的执行时间
    laravel 处理图片
    siege 压力测试工具的安装与使用
    laravel 实现点赞功能
  • 原文地址:https://www.cnblogs.com/nervendnig/p/11515957.html
Copyright © 2011-2022 走看看