zoukankan      html  css  js  c++  java
  • CCPC-Wannafly Winter Camp Day1 (Div2, onsite)

    Replay


    Dup4:

    • 要是不挂机,再多仔细想想就好了
    • J确实自闭好久,一直在想正确性,最后数据错了,喵喵喵?
    • 还是要保证充足的休息啊,中间睡了一小会儿,也不知道睡了多久,醒来他们就又过了一道
    • 要发掘题目更多的性质和有用条件啊,算法和数据结构只是工具,不要总想着这是啥题这是啥题,我会不会,其实我啥都不会

    X:

    • 日常挂机时间久,感觉是个不好的习惯。
    • 太久没写了,已经不会算复杂度了, TLE MLE到自闭,转身写了个dp就过了?
    • 感觉太容易根据数据想算法了, 自导自演。
    • 自导自演,顺便演了16的C,演技拉满

    A:机器人

    Upsolved.

    思路:

    考虑两种情况

    第一种是$b区没有站点需要经过,并且在a区只有一侧有站点需要经过的话$

    我们不需要走一个圈,直接从$s走出去到一个特殊点走回s即可$

    还有一种就是走一个矩形

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define ll long long
     5 #define INF 0x3f3f3f3f
     6 #define INFLL 0x3f3f3f3f3f3f3f3f
     7 int n, r, m, k, s;
     8 vector <int> v[2], p; 
     9 
    10 int main()
    11 {
    12     while (scanf("%d%d%d%d%d", &n, &r, &m, &k, &s) != EOF)
    13     {
    14         v[0].clear(); v[1].clear(); p.clear();
    15         for (int i = 1, x, y; i <= r; ++i)
    16         {
    17             scanf("%d%d", &x, &y);
    18             v[y].push_back(x);
    19         }
    20         sort(v[0].begin(), v[0].end());
    21         sort(v[1].begin(), v[1].end());  
    22         for (int i = 1, x; i <= m; ++i)
    23         {
    24             scanf("%d", &x);
    25             p.push_back(x);
    26         }    
    27         p.push_back(1); p.push_back(n); 
    28         sort(p.begin(), p.end());
    29         p.erase(unique(p.begin(), p.end()), p.end());  
    30         int Max = 0; 
    31         int Min = INF;  
    32         if (!v[0].empty()) 
    33         {
    34             Max = max(Max, *v[0].rbegin()); 
    35             Min = min(Min, *v[0].begin());
    36         }
    37         if (!v[1].empty())
    38         {
    39             Max = max(Max, *v[1].rbegin());
    40             Min = min(Min, *v[1].begin()); 
    41         }
    42         int pos_Max = lower_bound(p.begin(), p.end(), Max) - p.begin();
    43         int pos_Min = upper_bound(p.begin(), p.end(), Min) - p.begin() - 1; 
    44         pos_Max = p[pos_Max];
    45         pos_Min = p[pos_Min];  
    46         ll res = INFLL;
    47         // b区不需要经过站点
    48         if (v[1].empty())
    49         {
    50             if (Max <= s) pos_Max = s;  
    51             if (Min >= s) pos_Min = s;  
    52             ll tmp = 2ll * (pos_Max - pos_Min);
    53             res = min(res, tmp);
    54         }
    55         // 走矩形路线
    56         if (!v[1].empty())  
    57         {
    58             ll tmp = 2ll * (pos_Max - pos_Min);
    59             if (!v[1].empty()) tmp += 2ll * k; 
    60             if (s < pos_Min)  
    61                 tmp += 2ll * (pos_Min - s);
    62             if (s > pos_Max)
    63                 tmp += 2ll * (s - pos_Max);
    64             res = min(res, tmp); 
    65         }    
    66         printf("%lld
    ", res);  
    67     }
    68     return 0;
    69 }
    View Code

    B:吃豆豆

    Solved.

    思路:

    $dp[i][j][k]表示在(i, j)位置, 时间为t获得最多的糖果。$

    $那么, 很显然有转移方程$

    $dp[i][j][k] -> dp[i +1][j][k + 1]$

    $dp[i][j][k] -> dp[i - 1][j][k + 1]$

    $dp[i][j][k] -> dp[i][j + 1][k + 1]$

    $dp[i][j][k] -> dp[i][j - 1][k + 1]$

    $dp[i][j][k] -> dp[i][j][k + 1]$

    $当时间k\%T[i][j] == 0时, dp[i][j][k]++$

    $一共有n*m*c种状态, 复杂度是O(n*m*c)$

    $然后我也不知道我为啥写了个滚动数组$

     1 #include<bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 const int maxn = 10 + 10;
     6 
     7 int n, m, C;
     8 int sx, sy, ex, ey;
     9 int T[maxn][maxn];
    10 int arr[maxn][maxn];
    11 int brr[maxn][maxn];
    12 
    13 int main()
    14 {
    15     while(~scanf("%d %d %d", &n, &m, &C))
    16     {
    17         for(int i = 1; i <= n; ++i)
    18         {
    19             for(int j = 1; j <= m; ++j)
    20             {
    21                 scanf("%d", &T[i][j]);
    22             }
    23         }
    24         scanf("%d %d %d %d", &sx, &sy, &ex, &ey);
    25         memset(arr, -1, sizeof arr);
    26         arr[sx][sy] = 0;
    27         int step = 1;
    28         for(step = 1; ; step++)
    29         {
    30             for(int i = 1; i <= n; ++i)
    31             {
    32                 for(int j = 1; j <= m; ++j)
    33                 {
    34                     brr[i][j] = arr[i][j];
    35                 }
    36             }
    37             for(int i = 1; i <= n; ++i)
    38             {
    39                 for(int j = 1; j <= m; ++j)
    40                 {
    41                     if(i - 1 >= 1) arr[i][j] = max(arr[i][j], brr[i - 1][j]);
    42                     if(i + 1 <= n) arr[i][j] = max(arr[i][j], brr[i + 1][j]);
    43                     if(j - 1 >= 1) arr[i][j] = max(arr[i][j], brr[i][j - 1]);
    44                     if(j + 1 <= m) arr[i][j] = max(arr[i][j], brr[i][j + 1]);
    45                     if(step % T[i][j] == 0)
    46                     {
    47                         if(arr[i][j] >= 0) arr[i][j]++;
    48                     }
    49                 }
    50             }
    51             if(arr[ex][ey] >= C) break;
    52         }
    53         printf("%d
    ", step);
    54     }
    55     return 0;
    56 }
    View Code

    C:拆拆拆数

    Solved.

    思路:

    对于两个奇数,因为2和任意奇数都是互质的。

    所以可以拆成A(2,A-2),B(B-2,2)

    当有偶数的时候,假设A是偶数

    对于大于4的偶数,一定可以拆成一个奇质数和一个奇数之和,相应的将另一个数拆成一个2对应之前的奇数,剩下的只要做到与奇质数互质即可。

    因为3*5*7*11*13*17*19*23*29*31*37*41*43*47*53>1e9,所以B-2在53之前一定有一个奇质数不是B-2的因子。

      1 #include<bits/stdc++.h>
      2 
      3 using namespace std;
      4 
      5 typedef long long ll;
      6 
      7 ll GCD(ll a, ll b)
      8 {
      9     return b == 0 ? a : GCD(b, a % b);
     10 }
     11 
     12 ll a, b;
     13 ll prime[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53};//15
     14 
     15 
     16 int main()
     17 {
     18     int t;
     19     scanf("%d", &t);
     20     while(t--)
     21     {
     22         scanf("%lld %lld", &a, &b);
     23         if(GCD(a, b) == 1)
     24         {
     25             puts("1");
     26             printf("%lld %lld
    ", a, b);
     27             continue;
     28         }
     29         if(a == b)
     30         {
     31             if(a & 1)
     32             {
     33                 ll ans1 = a / 2;
     34                 ll ans2 = a - a / 2;
     35                 puts("2");
     36                 printf("%lld %lld
    ", ans1, ans2);
     37                 printf("%lld %lld
    ", ans2, ans1);
     38             }
     39             else 
     40             {
     41                 ll ans1 = a / 2 - 1;
     42                 ll ans2 = a - ans1;
     43                 puts("2");
     44                 printf("%lld %lld
    ", ans1, ans2);
     45                 printf("%lld %lld
    ", ans2, ans1);
     46             }
     47             continue;
     48         }
     49         if(a % 2 == 1 && b % 2 == 1)
     50         {
     51             ll ans1 = 2, ans2 = a - 2;
     52             ll ans3 = b - 2, ans4 = 2;
     53             puts("2
    ");
     54             printf("%lld %lld
    ", ans1, ans3);
     55             printf("%lld %lld
    ", ans2, ans4);
     56         }
     57         else
     58         {
     59             int isswap = 0;
     60             if(b % 2 == 0)
     61             {
     62                 swap(a, b);
     63                 isswap = 1;
     64             }
     65             int flag = 0;
     66             ll ans1, ans2, ans3, ans4;
     67             ans3 = b - 2;
     68             ans4 = 2;
     69             for(int i = 1; i <= 15 && prime[i] + 2 <= a; ++i)
     70             {
     71                 if((b - 2) % prime[i] != 0)
     72                 {
     73                     flag = 1;
     74                     ans1 = prime[i];
     75                     ans2 = a - prime[i];
     76                     break;
     77                 }
     78             }
     79             if(flag)
     80             {
     81                 if(isswap) 
     82                 {
     83                     swap(ans1, ans3);
     84                     swap(ans2, ans4);
     85                 }
     86                 puts("2");
     87                 printf("%lld %lld
    ", ans1, ans3);
     88                 printf("%lld %lld
    ", ans2, ans4);
     89                 continue;
     90             }
     91             ans3 = b - b % a - 1;
     92             ans4 = b - ans3;
     93             for(int i = 0; i <= 15 && prime[i] + 2<= a; ++i)
     94             {
     95                 ans1 = prime[i];
     96                 ans2 = a - prime[i];
     97                 if(GCD(ans1, ans3) == 1 && GCD(ans2, ans4) == 1)
     98                 {
     99                     flag = 1;
    100                     break;
    101                 }
    102             }
    103             if(flag)
    104             {
    105                 if(isswap)
    106                 {
    107                     swap(ans1, ans3);
    108                     swap(ans2, ans4);
    109                 }
    110                 puts("2");
    111                 printf("%lld %lld
    ", ans1, ans3);
    112                 printf("%lld %lld
    ", ans2, ans4);
    113             }
    114             else
    115             {
    116                 puts("-1");
    117             }
    118         }
    119     }
    120     return 0;
    121 }
    View Code

    好像直接暴力就行了?

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define ll long long
     5 int t; ll a, b;
     6 
     7 ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }
     8 void solve()
     9 {
    10     for (int i = 2; i <= min(a, 1ll * 100); ++i) for (int j = 2; j <= min(b, 1ll * 100); ++j) if (gcd(i, j) == 1 && gcd(a - i, b - j) == 1)
    11     {
    12         puts("2");
    13         printf("%d %d
    ", i, j);
    14         printf("%lld %lld
    ", a - i, b - j);
    15         return;
    16     }
    17 }
    18 
    19 int main()
    20 {
    21     scanf("%d", &t);
    22     while (t--)
    23     {
    24         scanf("%lld%lld", &a, &b);
    25         if (gcd(a, b) == 1) 
    26         {
    27             puts("1");
    28             printf("%lld %lld
    ", a, b);
    29         }
    30         else solve();
    31     }
    32     return 0;
    33 }
    View Code

    E:流流流动

    Upsolved.

    这些边连起来会形成一棵树、简单树形dp即可

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define N 210
     5 int n, f[N], d[N];
     6 vector <int> G[N];
     7 
     8 int pre[N];
     9 int find(int x) { return pre[x] == 0 ? x : pre[x] = find(pre[x]); }
    10 void join(int x, int y)
    11 {
    12     int fx = find(x), fy = find(y);
    13     if (fx != fy)
    14         pre[fx] = fy;
    15 }
    16 
    17 int dp[N][2];
    18 void DFS(int u, int fa)
    19 {
    20     dp[u][0] = 0;
    21     dp[u][1] = f[u];
    22     for (auto v : G[u]) if (v != fa)
    23     {
    24         DFS(v, u);
    25         dp[u][0] += max(dp[v][0], dp[v][1]);
    26         dp[u][1] += max(dp[v][0], dp[v][1] - d[min(u, v)]);
    27     }
    28 }
    29 
    30 int main()
    31 {
    32     while (scanf("%d", &n) != EOF)
    33     {
    34         for (int i = 0; i <= n; ++i) G[i].clear();
    35         memset(pre, 0, sizeof pre);
    36         memset(dp, 0, sizeof dp); 
    37         for (int i = 1; i <= n; ++i) scanf("%d", f + i);
    38         for (int i = 1; i <= n; ++i) scanf("%d", d + i); 
    39         for (int i = 2; i <= n; ++i)
    40         {
    41             if (i & 1)
    42             {
    43                 if (3 * i + 1 <= n)
    44                 {
    45                     G[3 * i + 1].push_back(i);
    46                     G[i].push_back(3 * i + 1);
    47                     join(3 * i + 1, i);            
    48                 }
    49             }
    50             else
    51             {
    52                 G[i].push_back(i / 2);
    53                 G[i / 2].push_back(i); 
    54                 join(i, i / 2);
    55             }
    56         }
    57         for (int i = 1; i <= n; ++i) if (!pre[i])
    58         {
    59             G[0].push_back(i); 
    60             G[i].push_back(0);
    61         }
    62         DFS(0, 0); 
    63         printf("%d
    ", max(dp[0][0], dp[0][1]));
    64     }
    65     return 0;
    66 }
    View Code

    F:爬爬爬山

    Solved.

    思路:

    考虑海拔和体力的关系,即最高可以爬的山为$h[1] + k$

    那么对于其他高度不符合的山,我们就需要降低其高度

    可以理解为点有点权,边有边权,经过边和点都要加上其权值,求最短路

    将一个点拆成两个点,中间连条有向边,权值为该点点权,再跑最短路即可

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define ll long long
     5 #define N 200010
     6 #define INFLL 0x3f3f3f3f3f3f3f3f
     7 int n, m, k, h[N];
     8 ll d;
     9 struct Graph
    10 {
    11     struct node
    12     {
    13         int to, nx; ll w;
    14         node () {}
    15         node (int to, int nx, ll w) : to(to), nx(nx), w(w) {}
    16     }a[N << 3];
    17     int head[N], pos;
    18     void init()
    19     {
    20         memset(head, 0, sizeof head);
    21         pos = 0;
    22     }
    23     void add(int u, int v, ll w)
    24     {
    25         a[++pos] = node(v, head[u], w); head[u] = pos;
    26     }
    27 }G;
    28 #define erp(u) for (int it = G.head[u], v = G.a[it].to; it; it = G.a[it].nx, v = G.a[it].to)
    29 
    30 struct node
    31 {
    32     int to; ll w;
    33     node () {}
    34     node (int to, ll w) : to(to), w(w) {}
    35     bool operator < (const node &other) const { return w > other.w; }
    36 };
    37 ll dist[N]; bool used[N];
    38 void Dijkstra()
    39 {
    40     for (int i = 1; i <= 2 * n + 1; ++i) dist[i] = INFLL, used[i] = false;
    41     dist[2] = 0; priority_queue <node> pq; pq.push(node(2, 0));
    42     while (!pq.empty())
    43     {
    44         int u = pq.top().to; pq.pop();
    45         if (used[u]) continue;
    46         used[u] = true;
    47         erp(u) 
    48         {
    49             ll w = G.a[it].w;
    50             if (!used[v] && dist[v] > dist[u] + w)
    51             {
    52                 dist[v] = dist[u] + w;
    53                 pq.push(node(v, dist[v]));
    54             }
    55         }
    56     }
    57 }
    58 
    59 int main()
    60 {
    61     while (scanf("%d%d%d", &n, &m, &k) != EOF)
    62     {
    63         G.init();  
    64         for (int i = 1; i <= n; ++i) scanf("%d", h + i);
    65         d = h[1] + k;
    66         for (int i = 1, u, v, w; i <= m; ++i) 
    67         {
    68             scanf("%d%d%d", &u, &v, &w);
    69             G.add(2 * u + 1, 2 * v, w);
    70             G.add(2 * v + 1, 2 * u, w);
    71         }
    72         for (int i = 1; i <= n; ++i)
    73         {
    74             ll w = 0;
    75             if (h[i] > d) w = 1ll * (h[i] - d) * (h[i] - d);
    76             G.add(2 * i, 2 * i + 1, w);
    77         }
    78         Dijkstra();
    79         printf("%lld
    ", dist[2 * n + 1]);
    80     }
    81     return 0;
    82 }
    View Code

    I:起起落落

    Upsolved.

    思路:

    $f[i] 表示以i结尾的方案数$ 

    $f[i] = sumlimits_{j = 1}^{i - 1} [p[j] > p[i]] cdot f[j] cdot sumlimits_{k = j + 1}^{i - 1} [p[k] < p[i]]$

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define ll long long
     5 #define N 2010
     6 const ll MOD = (ll)1e9 + 7;
     7 int n, p[N];
     8 ll f[N];
     9 
    10 int main()
    11 {
    12     while (scanf("%d", &n) != EOF)
    13     {
    14         for (int i = 1; i <= n; ++i) scanf("%d", p + i); 
    15         memset(f, 0, sizeof f);
    16         for (int i = 3; i <= n; ++i)
    17         {
    18             int cnt = p[i - 1] < p[i]; 
    19             for (int j = i - 2; j >= 1; --j)   
    20             {
    21                 if (p[j] > p[i]) 
    22                     f[i] = (f[i] + (f[j] + 1) * cnt % MOD) % MOD;
    23                 else
    24                     ++cnt; 
    25             }
    26         }
    27         ll res = 0;
    28         for (int i = 3; i <= n; ++i) res = (res + f[i]) % MOD; 
    29         printf("%lld
    ", res);
    30     }
    31     return 0;
    32 }
    View Code

    Div1:

    用权值线段树来维护这个式子

    我们考虑$f[x]的方案只会对 y > x ;并且; p[y] < p[x] 的y产生贡献$

    产生贡献的次数是$z in [x + 1, y - 1] 中 p[z] < p[x] 的个数$

    我们对于$z in [x + 1, y - 1] 中,不管p[z] 与 p[x] 的大小关系$

    全都把次数算上

    再考虑删除多算的贡献

    对于$z in [x + 1, y - 1] 它多产生的贡献是 x in [1, z] ;并且; p[x] > p[z] 的 f[x] 之和$

    $那就是权值线段树上的 区间更新 单点更新 区间查询的操作$

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define ll long long
     5 #define N 100010
     6 const ll MOD = (ll)1e9 + 7;
     7 int n, p[N];
     8 
     9 void up(ll &x) { if (x >= MOD) x -= MOD; }
    10 namespace SEG
    11 {
    12     struct node
    13     {
    14         ll base, v, lazy;
    15         node () {}
    16         node (ll base, ll v, ll lazy) : base(base), v(v), lazy(lazy) {}
    17         void init() { base = v = lazy = 0; }
    18         node operator + (const node &other) const
    19         {
    20             node res; res.init();
    21             res.base = (base + other.base) % MOD;
    22             res.v = (v + other.v) % MOD; 
    23             return res;
    24         }    
    25     }a[N << 2], res;
    26     void init() { memset(a, 0, sizeof a); }
    27     void pushdown(int id)
    28     {
    29         if (!a[id].lazy) return;
    30         up(a[id << 1].lazy += a[id].lazy);
    31         up(a[id << 1 | 1].lazy += a[id].lazy);
    32         a[id << 1].v = (a[id << 1].v + a[id].lazy * a[id << 1].base % MOD) % MOD;
    33           a[id << 1 | 1].v = (a[id << 1 | 1].v + a[id].lazy * a[id << 1 | 1].base % MOD) % MOD;
    34         a[id].lazy = 0;    
    35     }
    36     void update(int id, int l, int r, int ql, int qr, ll v)
    37     {
    38         if (l >= ql && r <= qr)
    39         {
    40             up(a[id].lazy += v);
    41             a[id].v = (a[id].v + a[id].base * v % MOD) % MOD;
    42             return;
    43         }
    44         int mid = (l + r) >> 1;
    45         pushdown(id);
    46         if (ql <= mid) update(id << 1, l, mid, ql, qr, v);
    47         if (qr > mid) update(id << 1 | 1, mid + 1, r, ql, qr, v);
    48         a[id] = a[id << 1] + a[id << 1 | 1];
    49     }
    50     void update2(int id, int l, int r, int pos, ll base, ll v)
    51     {
    52         if (l == r)
    53         {
    54             up(a[id].base += base);
    55             up(a[id].v += v);
    56             return;
    57         }
    58         int mid = (l + r) >> 1;
    59         pushdown(id);
    60         if (pos <= mid) update2(id << 1, l, mid, pos, base, v);
    61         else update2(id << 1 | 1, mid + 1, r, pos, base, v);
    62         a[id] = a[id << 1] + a[id << 1 | 1];
    63     }
    64     void query(int id, int l, int r, int ql, int qr)
    65     {
    66         if (l >= ql && r <= qr)
    67         {
    68             res = res + a[id];
    69             return;
    70         }
    71         int mid = (l + r) >> 1;
    72         pushdown(id); 
    73         if (ql <= mid) query(id << 1, l, mid, ql, qr);
    74         if (qr > mid) query(id << 1 | 1, mid + 1, r, ql, qr);
    75     }
    76 }
    77 
    78 int main()
    79 {
    80     while (scanf("%d", &n) != EOF)
    81     {
    82         for (int i = 1; i <= n; ++i) scanf("%d", p + i);
    83         SEG::init();
    84         ll res = 0;
    85         for (int i = 1; i <= n; ++i)
    86         {
    87             SEG::res.init();
    88             SEG::query(1, 1, n, p[i] + 1, n); 
    89             up(res += SEG::res.v);
    90             SEG::update(1, 1, n, p[i] + 1, n, 1); 
    91             SEG::update2(1, 1, n, p[i], SEG::res.v + 1, (-SEG::res.base + MOD) % MOD); 
    92         }
    93         printf("%lld
    ", res);   
    94     }
    95     return 0;
    96 }
    View Code

    J:夺宝奇兵

    Solved.

    思路:

    考虑居民拥有的最大宝物数为$m$

    可以枚举这个值,贪心$check()$即可

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define ll long long
     5 #define N 1010
     6 int n, m;
     7 vector <int> v[N];
     8 
     9 ll check(int x)
    10 {
    11     ll res = 0;
    12     int cnt = 0;
    13     priority_queue <int, vector <int>, greater <int> > q;
    14     for (int i = 1; i <= n; ++i)
    15     {
    16         int need = v[i].size() - x;
    17         for (auto it : v[i])
    18         {
    19             if (need > 0)
    20             {
    21                 --need;
    22                 res += it;
    23                 ++cnt;
    24             }
    25             else 
    26                 q.push(it);
    27         }
    28     }
    29     while (cnt <= x)  
    30     {
    31         ++cnt;
    32         res += q.top(); q.pop();    
    33     }
    34     return res;
    35 }
    36 
    37 int main()
    38 {
    39     while (scanf("%d%d", &n, &m) != EOF)
    40     {
    41         for (int i = 1; i <= n; ++i) v[i].clear();
    42         for (int i = 1, a, c; i <= m; ++i) 
    43         {
    44             scanf("%d%d", &a, &c);
    45             v[c].push_back(a);
    46         }
    47         for (int i = 1; i <= n; ++i) sort(v[i].begin(), v[i].end());
    48         ll res = (ll)1e18; 
    49         for (int i = 0; i < m; ++i) 
    50             res = min(res, check(i));
    51         printf("%lld
    ", res);
    52     }
    53     return 0;
    54 }
    View Code

    Div1:

    从大到小枚举$x$, 发现在大的$x的情况下会买掉的,在小的x下一定会买掉$

    $每件物品最多操作一次,再用线段树维护前k小之和即可$

    复杂度$O(nlogn)$

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 
      4 #define ll long long
      5 #define N 100010
      6 #define pii pair <int, int>
      7 int n, m;
      8 struct node
      9 {
     10     int a, c;
     11     void scan() { scanf("%d%d", &a, &c); }
     12     bool operator < (const node &other) const { return a < other.a; }
     13 }arr[N];
     14 queue <pii> q[N];
     15 vector <int> vec[N];
     16 
     17 namespace SEG
     18 {
     19     ll v[N << 2]; int cnt[N << 2];
     20     void pushup(int id) { v[id] = v[id << 1] + v[id << 1 | 1]; cnt[id] = cnt[id << 1] + cnt[id << 1 | 1]; }
     21     void build(int id, int l, int r)
     22     {
     23         v[id] = 0; cnt[id] = 0;
     24         if (l == r)
     25         {
     26             v[id] = arr[l].a;
     27             cnt[id] = 1;
     28             return;
     29         }
     30         int mid = (l + r) >> 1;
     31         build(id << 1, l, mid);
     32         build(id << 1 | 1, mid + 1, r);
     33         pushup(id);
     34     }
     35     void update(int id, int l, int r, int pos)
     36     {
     37         if (l == r)
     38         {
     39             v[id] = 0;
     40             cnt[id] = 0;
     41             return;
     42         }
     43         int mid = (l + r) >> 1;
     44         if (pos <= mid) update(id << 1, l, mid, pos);
     45         else update(id << 1 | 1, mid + 1, r, pos);
     46         pushup(id);
     47     }
     48     ll query(int id, int l, int r, int k)
     49     {
     50         if (k <= 0) return 0;
     51         if (k == cnt[id]) return v[id];
     52         int mid = (l + r) >> 1;
     53         ll res = 0;
     54         res += query(id << 1, l, mid, min(k, cnt[id << 1]));
     55         if (k - cnt[id << 1] > 0) res += query(id << 1 | 1, mid + 1, r, k - cnt[id << 1]);
     56         return res;
     57     }
     58 }
     59 
     60 ll tmp;
     61 int cnt;
     62 void work(int x)
     63 {
     64     if (x - 1) for (auto it : vec[x]) vec[x - 1].push_back(it);
     65     for (auto it : vec[x]) 
     66     {
     67         pii top = q[it].front(); q[it].pop();
     68         ++cnt;
     69         tmp += top.first;
     70         SEG::update(1, 1, m, top.second);    
     71     }
     72 }
     73 
     74 int main()
     75 {
     76     while (scanf("%d%d", &n, &m) != EOF)
     77     {
     78         for (int i = 1; i <= m; ++i) arr[i].scan();
     79         sort(arr + 1, arr + 1 + m);
     80         for (int i = 1; i <= m; ++i) q[arr[i].c].push(pii(arr[i].a, i)); 
     81         SEG::build(1, 1, m);
     82         for (int i = 1; i <= n; ++i) vec[q[i].size()].push_back(i);
     83         ll res = (ll)1e18; tmp = 0; cnt = 0;
     84         if (!vec[m].empty())
     85         {
     86             ++cnt;
     87             int it = *vec[m].begin();
     88             pii top = q[it].front(); q[it].pop();
     89             vec[m - 1].push_back(it); 
     90             tmp += top.first;
     91             SEG::update(1, 1, m, top.second); 
     92         }
     93         for (int i = m - 1; i >= 0; --i)
     94         {
     95             work(i);
     96             res = min(res, tmp + SEG::query(1, 1, m, i - cnt));
     97         }    
     98         printf("%lld
    ", res);
     99     }    
    100     return 0;
    101 }
    View Code
  • 相关阅读:
    赫尔维茨公式
    从解析几何的角度分析二次型
    Struts 1 Struts 2
    记一次服务器被入侵的调查取证
    契约式设计 契约式编程 Design by contract
    lsblk df
    Linux Find Out Last System Reboot Time and Date Command 登录安全 开关机 记录 帐号审计 历史记录命令条数
    Infrastructure for container projects.
    更新文档 版本控制 多版本并发控制
    Building Microservices: Using an API Gateway
  • 原文地址:https://www.cnblogs.com/Dup4/p/10296448.html
Copyright © 2011-2022 走看看