zoukankan      html  css  js  c++  java
  • 2020.7.19 排位赛(二)

    2020/7/19 排位赛(二)

    A Colliding Balls

    solution

    1. 两个球碰撞的条件: xi * ui = yj * vj;
    2. 每个球在碰撞后会消失,一个球如果能和多个球碰撞,那么首先会和坐标值最小的碰撞。
    3. 用muiltiset。

    code

    /*******************
    Problem:
    Author:CXY1999
    Status:Coding
    Head Vision 2.1
    *******************/
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<climits>
    #include<vector>
    #include<set>
    #include<cmath>
    #include<queue>
    #include<utility>
    #include<algorithm>
    
    #define pb push_back
    #define BG begin()
    #define ED end()
    typedef long long LL;
    using namespace std;
    multiset<LL> s;
    
    int main() {
        ios::sync_with_stdio(0);
        int n, m;
        cin >> n >> m;
        for (int i = 0; i < n; i++) {
            LL l, r;
            cin >> l >> r;
            s.insert(l * r);
        }
        int Ans = 0;
        for (int i = 0; i < m; i++) {
            LL l, r;
            cin >> l >> r;
            if (s.count(l * r)) {
                multiset<LL>::iterator t = s.find(l * r);
                s.erase(t);
                Ans++;
            }
        }
        cout << Ans << endl;
    }
    

    B Awkwardness Minimization

    solution

    交叉着排,剩余的放两边。然而不会证明…
    思路: 可以先猜出一个解,然后看交换任意两个结果会不会更优/差。
    以后遇到这类问题可以打表,打表,打表!

    code

    #include<iostream>
    #include<string>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    using namespace std;
    #define MP make_pair
    #define fi first
    #define se second
    #define pb push_back
    typedef long long ll;
    typedef pair<int, int> pii;
    int T;
    string str;
    long long he(ll tail,ll size)
    {
        long long ans=(1+tail)*size/2;
        return ans;
    }
    int main()
    {
        cin>>T;
        while(T--)
        {
            cin>>str;
            ll cntb=0,cntg=0;
            for(ll i=0; i<str.size(); i++)
            {
                if(str[i]=='b')
                    cntb++;
                else
                    cntg++;
            }
            long long ans=0;
            ll dis=abs(cntb-cntg);
            ll cnt=min(cntb,cntg);
            for(ll i=1; i<=cnt; i++)
            {
                ans+=(i*2-1)*((cnt-i+1)*2-1);
                //    数值        个数
            }
    //		cout<<"temp:"<<ans<<endl;
            if(cntb!=cntg)
            {
                ll g0=he(cnt*2-1,cnt);
                ans+=g0;
                dis--;    
                ans+=g0*(dis/2)*2+cnt*he(dis/2,dis/2)*2;
                if(dis%2==1)
                    ans+=g0+cnt*(dis/2+1);
    //
    //	//		ans+= (1+cnt*2-1)*cnt/2*dis+cnt*( 1+(dis/2) )
    //			ans+= he(1+cnt*2-1,cnt)*dis+cnt*he((dis-1)/2,(dis-1)/2)*2;
    //				//     累加和  * 个数     + 多增加cnt个数
    //	//		ans+= he(1+cnt*2-1,cnt)*dis+cnt*(dis/2);
    //			if(dis%2==0)
    //				ans+=cnt+dis/2+1;
            }
            cout<<ans<<endl;
        }
        return 0;
    }
    /*
    7
    gb
    bgg
    bbgg
    bbbggg
    bbbgb
    bbbggggggggggg
    bbbgggg
    
    //
    1
    2
    6
    19
    6
    139 ? ggggg bgbb ggggg
    
    */
    

    C Special Graph Construction

    solution

    1. 设顶点数为 n,则边数 m = n*3/2;
    2. 把每个连通块看成一个顶点的话,图是一个有 k 条边,k+1 个顶点的树。
      • k>=1
        要想整个图是一个二分图,则去掉桥后,每个连通块是一个二分图。在树的叶子节点连通块内,有一个顶点的度数为2(因为去掉了桥边),其他顶点度数为3,显然不能构成二分图(二分图两边点集的度数和相等)。所以至少得去掉一个边,对于一个节点数大于1(即k>=1)的树来说,叶子节点至少为2,所以说至少得去掉两条边才能保证是二分图,即f(G)>=2.
      • k=0
        直接输出样例
    3. 构造
      构造图见官方题解

    code

    #include <bits/stdc++.h>
    
    using namespace std;
    
    int main() {
        int k;
        scanf("%d", &k);
        if (k == 0) {
            printf("6 9
    1 4
    1 5
    1 6
    2 4
    2 5
    2 6
    3 4
    3 5
    3 6
    0
    ");
            return 0;
        }
        int n = 10 + (k - 1) * 6, m = n * 3 / 2;
        printf("%d %d
    ", n, m);
        for (int i = 1; i < 5; ++i) {
            printf("%d %d
    ", i, i + 1);
        }
        printf("1 5
    ");
        printf("1 3
    2 4
    ");
    
        for (int i = 6; i < 10; ++i) {
            printf("%d %d
    ", i, i + 1);
        }
        printf("6 10
    ");
        printf("6 8
    7 9
    ");
    
        int now = 5, n1 = 11;
        for (int i = 1; i < k; ++i) {
            printf("%d %d
    ", now, n1);
            for (int j = n1; j < n1 + 5; ++j) {
                printf("%d %d
    ", j, j + 1);
            }
            for (int j = 0; j < 3; ++j) {
                printf("%d %d
    ", n1 + j, n1 + j + 3);
            }
            now = n1 + 5;
            n1 = now + 1;
        }
        printf("%d %d
    ", now, 10);
        printf("2 2 9
    ");
        return 0;
    }
    

    D Minimum Variance

    solution

    要求: 方差的最小值 * n2 = n * (平方的和) - (和的平方).

    1. 正解
      直接枚举平均值,然后计算方差的最小值,直接计算会超时,要用到扫描线。
    2. 看不懂的解法
      先从最小平均值开始,不断迭代。其实原理和扫描线算法是一样的。

    code

    1. 正解

      #include <bits/stdc++.h>
      using namespace std;
      const int N = 50000 + 10;
      
      int n, sz[N];
      vector<int> vec[N];
      vector< pair<int,int> > issues[N];
      typedef long long LL;
      
      LL sum = 0, sum2 = 0;
      void rep(LL x, LL y) {
          sum2 -= x*x, sum -= x;
          sum2 += y*y, sum += y;
      }
      
      LL getAns() {
          return sum2 * n - sum * sum;
      }
      LL ans = 1e18;
      LL tackle() {
          sum2 = 0, sum = 0;
          for (int i = 1; i <= n; i ++) {
              sum += vec[i][0];
              sum2 += 1LL * vec[i][0] * vec[i][0];
              // printf("# %lld
      ", vec[i][0]);
          }
         //  printf("ans = %lld
      ", getAns());
          ans = min(ans, getAns());
          for (int i = 1; i <= 50000; i ++) {
              for (auto p: issues[i]) {
                  rep(p.first, p.second);
              }
              ans = min(ans, getAns());
          }
      }
      
      int main() {
          scanf("%d", &n);
          for (int i = 1; i <= n; i ++) {
              scanf("%d", &sz[i]);
              for (int j = 0; j < sz[i]; j ++) {
                  int x; scanf("%d", &x);
                  vec[i].push_back(x);
              }
              sort(vec[i].begin(), vec[i].end());
          }
          // RIG
          for (int i = 1; i <= n; i ++) {
              for (int j = 0; j + 1 < vec[i].size(); j ++) {
                  int l = vec[i][j], r = vec[i][j+1];
                  if ((r - l) % 2 == 0) {
                      issues[(l+r)/2].push_back(make_pair(vec[i][j], vec[i][j+1]));
                  } else {
                      issues[(l+r+1)/2].push_back(make_pair(vec[i][j], vec[i][j+1]));
                  }
              }
          }
          tackle();
          // LEF
          for (int i = 1; i <= 50000; i ++) issues[i].clear();
          for (int i = 1; i <= n; i ++) {
              for (int j = 0; j + 1 < vec[i].size(); j ++) {
                  int l = vec[i][j], r = vec[i][j+1];
                  if ((r - l) % 2 == 0) {
                      issues[(l+r)/2+1].push_back(make_pair(vec[i][j], vec[i][j+1]));
                  } else {
                      issues[(l+r+1)/2].push_back(make_pair(vec[i][j], vec[i][j+1]));
                  }
              }
          }
          tackle();
          cout << ans << endl;
      }
      
    2. 其他

      #include<bits/stdc++.h>
      using namespace std;
      typedef pair<int, int> pii;
      typedef long long ll;
      #define fi first
      #define se second
      #define all(x) (x).begin(),(x).end()
      const int N = 5e4 + 10;
      vector<pii> T[N];
      
      int main() {
      #ifdef local
          freopen("in.txt", "r", stdin);
      #endif
          ios::sync_with_stdio(false);
          cin.tie(0), cout.tie(0);
          int n; cin >> n;
          vector<int> v;
          ll d2 = 0, d = 0;
          for(int i = 0; i < n; i++) {
              int sz; cin >> sz;
              v.resize(sz);
              for(auto &e : v) cin >> e;
              sort(all(v));
              for(int i = 0; i + 1 < sz; i++) {
                  int t = (v[i] + v[i + 1] + 1) / 2;
                  T[t].emplace_back(v[i], v[i + 1]);
              }
              d2 += (ll) v[0] * v[0];
              d += v[0];
          }
          ll ans = n * d2 - d * d;
          for(int i = 0; i < N; i++) {
              if(T[i].empty()) continue;
              for(auto &e : T[i]) {
                  d -= e.fi;
                  d2 -= (ll) e.fi * e.fi;
                  d += e.se;
                  d2 += (ll) e.se * e.se;
              }
              ans = min(ans, n * d2 - d * d);
          }
          cout << ans << '
      ';
          return 0;
      }
      

    E Colorful Balloons (搁置)

    要用到fft。

    F Recover Array

    solution

    分成三个一组,先查询这一组的和 sum;

    1. sum = 3 或 sum = 0 则这一组的值就全知道了(查询次数为1);
    2. sum = 1, 随机查询三个位置中的一个,设值为 x ;
      • x = 1, 则其余两个值为0(查询次数为2);
      • x = 0, 则还得再查询一次(查询次数为3);
    3. sum = 2, 与 sum = 1 同理。

    可以证明这样能在9e4次查询内求出结果的概率非常大(我不会证qwq)。

    code

    #include <bits/stdc++.h>
    
    using namespace std;
    int n = 1e5;
    int a[100010];
    
    int ask(int l, int r) {
        int res;
        printf("1 %d %d
    ", l, r);
        fflush(stdout);
        scanf("%d", &res);
        return res;
    }
    
    int main() {
        srand(time(0));
        for (int i = 1; i + 2 <= n; i += 3) {
            int sum = ask(i, i + 2);
            if (sum == 3) {
                a[i] = a[i + 1] = a[i + 2] = 1;
            } else if (sum == 0) {
                a[i] = a[i + 1] = a[i + 2] = 0;
            } else {
                int r = rand() % 3;
                int r2 = (r + 1) % 3, r3 = (r + 2) % 3;
                a[i + r] = ask(i + r, i + r);
                if (a[i + r] && sum == 1) {
                    a[i + r2] = a[i + r3] = 0;
                } else if (!a[i + r] && sum == 2) {
                    a[i + r2] = a[i + r3] = 1;
                } else {
                    a[i + r2] = ask(i + r2, i + r2);
                    a[i + r3] = sum - a[i + r2] - a[i + r];
                }
            }
        }
        a[n] = ask(n, n);
        printf("2");
        for (int i = 1; i <= n; ++i) {
            printf(" %d", a[i]);
        }
        fflush(stdout);
    }
    

    G Train or Walk

    solution

    签到题

    code

    #include <bits/stdc++.h>
    using namespace std;
    int ps[20010];
    int main() {
        int T; scanf("%d", &T);
        while(T--) {
            int n,a,b,c,d,p,q,y;
            scanf("%d%d%d%d%d%d%d%d", &n,&a,&b,&c,&d,&p,&q,&y);
            for(int i = 1; i<=n; ++i)
                scanf("%d", &ps[i]);
            int ans = abs(ps[b]-ps[a])*p;
            int tmp = abs(ps[c]-ps[a])*p;
            if(tmp>y) {
                tmp = 2e9;
            }else {
                tmp = y;
                tmp+=abs(ps[d]-ps[c])*q;
                tmp+=abs(ps[b]-ps[d])*p;
            }
            printf("%d
    ",min(ans,tmp));
        }
        return 0;
    
    }
    

    H Substring Matching (搁置)

    本场比赛最难的题,不会。好像是动态规化+单调队列。

    I Direct Segments (搁置)

    好像是2-sat的板子

    K Chef and Diamonds

    一个非常不错的期望题,我一开始只想出来了一个O(n)的算法,超时,我想着优化,结果是一开始的思路就错了。

    solution

    n个巧克力,q个钻石。
    考虑一个巧克力的位置,可能在第0个钻石后面第1个钻石前面,1个钻石后面第2个钻石前面…q个钻石后面,巧克力在q个钻石后面的概率为1/(q+1),则总共n个钻石,在q个钻石后面的巧克力个数的期望是 n * (1/(q+1).
    则去除q个钻石所需次数的期望是 n+q - n * (1/(q+1)).

    code

    #include <bits/stdc++.h>
    using namespace std;
    typedef double db;
    typedef long long ll;
    int T;
    int main() {
        scanf("%d", &T);
        while(T--){
            db n,q;
            scanf("%lf%lf", &n,&q);
            printf("%.9lf
    ",n+q-(q/(n+1)));
        }
    }
    

    L Analytics Load Jobs

    solution

    一个题意比较复杂的二分答案,读懂题意就能做了。

    code

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 100010;
    int n,K,J;
    int id[N],c[N][3];
    bool pd(int lim) {
        int cntJ = 0, cntK;
        for(int i = 1; i <= id[0]; ++i) {
            ++cntJ; cntK = 0;
            int t1 = c[i][1],t2= c[i][2];
            if(t2&&lim<2) return 0;
            if(t1&&lim<1) return 0;
            while(t1||t2){
                ++cntK;
                int t = lim;
                while(t>=2&&t2) {
                    t-=2; --t2;
                }
                while(t&&t1) {
                    --t; --t1;
                }
            }
            if(cntK > K) {
                cntJ+=ceil((double)(cntK-K)/K);
            }
        }
        return cntJ<=J;
    }
    int main() {
        int T; scanf("%d", &T);
        while(T--) {
            memset(id, 0, sizeof(id));
            memset(c,0,sizeof(c));
            scanf("%d%d%d", &n,&K,&J);
            for(int i = 1; i<=n; ++i) {
                int x,y; scanf("%d%d", &x,&y);
                if(!id[x]) id[x] = ++id[0];
                ++c[id[x]][y];
            }
            int l = 1,r = 2*n,mid,ans;
            while(l<=r) {
                mid = (l+r)/2;
                if(pd(mid)){
                    ans = mid; r = mid-1;
                }else l = mid+1;
            }
            printf("%d
    ",ans);
        }
    }
  • 相关阅读:
    读懂diff
    Sqlite数据库的加密
    SQLite 数据类型
    SQLite 混合模式程序集是针对“v2.0.50727”版的运行时生成的,在没有配置其他信息的情况下,无法在 4.0 运行时中加载该程序集。
    datatable写入sqlite
    使用NSSM将exe封装为服务
    Java OPC client开发踩坑记
    最终解决:win10小娜无法使用(win10 win+q 无法搜索应用程序)
    OPC DA 客户端实例[.net]
    KepServer作为OPC UA服务器以及建立OPC UA客户端
  • 原文地址:https://www.cnblogs.com/huihao/p/13347637.html
Copyright © 2011-2022 走看看