zoukankan      html  css  js  c++  java
  • [codeforces#592Div2]C-G题

    题目链接

    感觉这场难度迷茫,个人觉得难度排序为$A<B<D=E=G<C<F$


    C题:

    比赛结束1500+pp,结果出分900+fst,我就是fst的睿智Orz。

    题意为给出$n,p,w,d$,求满足下列式子的任意$x,y,z$

    $x*w+y*d=p&& x+y+z=n&&xgeq 0&&ygeq 0&&zgeq 0$

    如果不看$z$,式子的前半段就是扩展欧几里得,所以先求出式子$x*w+y*d=p$的一种解$(x,y)$,然后再判断解的合法性,并将解转化成合法的。

    由于求解时会爆longlong,所以用的java。

     1 import java.math.BigInteger;
     2 import java.util.*;
     3 public class Main {
     4     public static BigInteger x,y;
     5     public static void main(String[] args) {
     6         Scanner in = new Scanner(System.in);
     7         BigInteger n,p,w,d,gcd,xx,yy;
     8         n = in.nextBigInteger();
     9         p = in.nextBigInteger();
    10         w = in.nextBigInteger();
    11         d = in.nextBigInteger();
    12         gcd = exgcd(w,d);
    13         if(p.mod(gcd)!=BigInteger.ZERO) {
    14             System.out.printf("-1
    ");
    15             return ;
    16         }
    17         x=x.multiply(p.divide(gcd));
    18         y=y.multiply(p.divide(gcd));
    19         BigInteger lcm = w.divide(gcd).multiply(d);
    20         xx = lcm.divide(w);
    21         yy = lcm.divide(d);
    22         if (x.compareTo(BigInteger.ZERO)==-1 &&y.compareTo(BigInteger.ZERO)==-1) {
    23             System.out.printf("-1
    ");
    24             return ;
    25         }
    26         if (x.compareTo(BigInteger.ZERO)==-1) {
    27             x=x.add (y.divide(yy).multiply(xx));
    28             y=y.mod(yy);
    29         }
    30         else if (y.compareTo(BigInteger.ZERO)==-1) {
    31             y=y.add (x.divide(xx).multiply(yy));
    32             x=x.mod(xx);
    33         }
    34         if (x.add(y).compareTo(n)!=1 && x.compareTo(BigInteger.ZERO)!=-1 && y .compareTo(BigInteger.ZERO)!=-1) {
    35             System.out.print(x);
    36             System.out.print(" ");
    37             System.out.print(y);
    38             System.out.print(" ");
    39             System.out.print(n.subtract(x.add(y)));
    40             return ;
    41         }
    42         x=x.add (y.divide(yy).multiply(xx));
    43         y=y.mod(yy);
    44         if (x.add(y).compareTo(n)!=1 && x.compareTo(BigInteger.ZERO)!=-1 && y.compareTo(BigInteger.ZERO)!=-1&&x.multiply(w).add(y.multiply(d)).compareTo(p)==0) {
    45             System.out.print(x);
    46             System.out.print(" ");
    47             System.out.print(y);
    48             System.out.print(" ");
    49             System.out.print(n.subtract(x.add(y)));
    50             return ;
    51         }
    52         else {
    53             System.out.printf("-1
    ");
    54             return ;
    55         }
    56     }
    57     public static BigInteger exgcd(BigInteger a,BigInteger b) {
    58         if (b == BigInteger.ZERO) {
    59             x = BigInteger.ONE;
    60             y = BigInteger.ZERO;
    61             return a;
    62         }
    63         BigInteger g = exgcd(b, a.mod(b));
    64         BigInteger t = x;
    65         x = y;
    66         y =t.subtract((a.divide(b)).multiply(y));
    67         return g;
    68     }
    69 }

    D题:

    题意是给一棵树每个点染色,一共三种颜色,求染色花费最少并且相邻的三个点颜色不能重复。

    因为相邻的三个点颜色不能一样,所以树上每个点的度都要$leq 2$,即只有链才能染色。而链上染色只有$6$种方法,所以枚举$6$次即可。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int maxn = 2e5 + 10;
     5 const ll inf = 1e18;
     6 ll a[maxn][5], ans[maxn];
     7 vector<int>p[maxn];
     8 int cnt[10][3] = { {1,2,3},{2,1,3},{3,1,2},{1,3,2},{2,3,1},{3,2,1} };
     9 ll dfs(int x, int fa, int w, int t) {
    10     ll ans = a[x][cnt[w][t]];
    11     for (int i = 0; i < p[x].size(); i++) {
    12         int y = p[x][i];
    13         if (y == fa)continue;
    14         ans += dfs(y, x, w, (t + 1) % 3);
    15     }
    16     return ans;
    17 }
    18 void dfs1(int x, int fa, int w, int t) {
    19     ans[x] = cnt[w][t];
    20     for (int i = 0; i < p[x].size(); i++) {
    21         int y = p[x][i];
    22         if (y == fa)continue;
    23         dfs1(y, x, w, (t + 1) % 3);
    24     }
    25 }
    26 int main() {
    27     int n;
    28     scanf("%d", &n);
    29     for (int j = 1; j <= 3; j++)
    30         for (int i = 1; i <= n; i++)
    31             scanf("%lld", &a[i][j]);
    32     int f = 0, root = 1;
    33     for (int i = 1, x, y; i < n; i++) {
    34         scanf("%d%d", &x, &y);
    35         p[x].push_back(y);
    36         p[y].push_back(x);
    37         if (p[x].size() > 2 || p[y].size() > 2)
    38             f = 1;
    39     }
    40     for (int i = 1; i <= n; i++)
    41         if (p[i].size() == 1)
    42             root = i;
    43     if (f == 1)
    44         printf("-1
    ");
    45     else {
    46         ll Min = inf, ansi = 0;
    47         for (int i = 0; i < 6; i++) {
    48             ll t = dfs(root, 0, i, 0);
    49             if (Min > t)
    50                 Min = t, ansi = i;
    51         }
    52         printf("%lld
    ", Min);
    53         dfs1(root, 0, ansi, 0);
    54         for (int i = 1; i <= n; i++)
    55             printf("%lld%c", ans[i], i == n ? '
    ' : ' ');
    56     }
    57 }

    E题:

    题意说有$n$个数,有一种操作可以让一个数$+1$或$-1$,问最多$k$次操作后$min(max(a_{i})-min(a_{i}))$的值。

    排序后记录一下每种数的个数,然后从首尾扫,判断哪种数的个数少,然后就乱搞。感觉比之前的要简单...

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int maxn = 2e5 + 10;
     5 ll a[maxn];
     6 pair<ll, ll>b[maxn];
     7 int main() {
     8     ll n, k, cnt = 0, num = 0;
     9     scanf("%lld%lld", &n, &k);
    10     for (int i = 1; i <= n; i++)
    11         scanf("%lld", &a[i]);
    12     sort(a + 1, a + 1 + n);
    13     for (int i = 1; i <= n + 1; i++) {
    14         if (a[i - 1] && a[i] != a[i - 1])
    15             b[++cnt] = pair<ll, ll>(a[i - 1], num), num = 0;
    16         num++;
    17     }
    18     ll l = 1, r = cnt;
    19     while (k && l != r) {
    20         if (b[l].second <= b[r].second) {
    21             int cg = min(b[l + 1].first - b[l].first, k / b[l].second);
    22             if (cg == 0)break;
    23             b[l].first += cg;
    24             k -= b[l].second * cg;
    25             if (b[l].first == b[l + 1].first)b[l + 1].second += b[l].second, l++;
    26         }
    27         else {
    28             int cg = min(b[r].first - b[r-1].first, k / b[r].second);
    29             if (cg == 0)break;
    30             b[r].first -= cg;
    31             k -= b[r].second * cg;
    32             if (b[r].first == b[r-1].first)b[r - 1].second += b[r].second, r--;
    33         }
    34     }
    35     printf("%lld
    ", b[r].first - b[l].first);
    36 }

    F题:

    题意是说一个有n个黑白点的环,操作k次,每次操作时对于每个点,点$i$的颜色变为$i,i-1,i+1$三个点颜色的众数,即为点$i-1$为黑,点$i+1$为黑,点$i$为白,则点$i$为黑。

    大致画几个图就会发现,如果有两个即以上的相邻点同色,则块内的点的颜色永远都不会被改变。

    所以我们只要找到每个点到达最终状态需要多少次就可以得到,将所有在块内的点初始为0,其余的状态扫正反扫两遍可以得到。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int maxn = 2e5 + 10;
     5 char s[200010];
     6 int vis[200010];
     7 int main() {
     8     memset(vis, 0x3f, sizeof(vis));
     9     int n, k;
    10     scanf("%d%d", &n, &k);
    11     scanf("%s", s);
    12     for (int i = 0; i < n; i++)
    13         if (s[i] == s[(i + 1) % n] || s[i] == s[(i - 1 + n) % n])
    14             vis[i] = 0;
    15     for (int i = 2 * n - 1; i >= 0; i--)
    16         vis[i % n] = min(vis[i % n], vis[(i + 1) % n] + 1);
    17     for (int i = 0; i < 2 * n; i++)
    18         vis[i % n] = min(vis[i % n], vis[(i - 1 + n) % n] + 1);
    19     for (int i = 0; i < n; i++)
    20         if (min(vis[i], k) % 2 == 1)
    21             printf("%c", 'W' + 'B' - s[i]);
    22         else
    23             printf("%c", s[i]);
    24     return 0;
    25 }

    G题:

    题意是说有两个队列$q,p$,每个队列有$n$个人,编号为$1-n$,求最大的$ans=sum_{i=1}^{n}max(p_{i},q_{i})&&ansleq k$

    先固定一个序列$q$,为$1,2,3cdot cdot cdot n$,然后去构造序列$p$。

    序列$p$初始也为$1,2,3cdot cdot cdot n$,如果交换$p_{1},p_{n}$后的答案小于等于$k$,则交换,然后判断能否交换$p_{2},p_{n-1}$。

    如果交换$p_{1},p_{n}$后的答案大于$k$,则直接找到位置$x$,使得交换$p_{1},p_{x}$后答案等于k。依次类推。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int maxn = 2e6 + 10;
     5 int ans[maxn];
     6 int main() {
     7     ll n, k;
     8     scanf("%lld%lld", &n, &k);
     9     ll sum = (n + 1) * n >> 1;
    10     if (k < sum) {
    11         printf("-1
    ");
    12         return 0;
    13     }
    14     for (int i = 1; i <= n; i++)
    15         ans[i] = i;
    16     int l = 1, r = n;
    17     while (l < r) {
    18         if (sum + r - l <= k) {
    19             swap(ans[l], ans[r]);
    20             sum += r - l; l++; r--;
    21         }
    22         else {
    23             int p = k - sum + l;
    24             swap(ans[l], ans[p]);
    25             sum += p - l;
    26             break;
    27         }
    28     }
    29     printf("%lld
    ", sum);
    30     for (int i = 1; i <= n; i++)
    31         printf("%d%c", i, i == n ? '
    ' : ' ');
    32     for (int i = 1; i <= n; i++)
    33         printf("%d%c", ans[i], i == n ? '
    ' : ' ');
    34 
    35 }

  • 相关阅读:
    缓存
    mybatis(ibatis)理解
    hibernate理解
    linux vi 命令
    Activity中ConfigChanges属性的用法
    sendStickyBroadcast和sendStickyOrderedBroadcast
    广播 BroadCastReceiver
    Android四大基本组件介绍与生命周期
    ubuntu14.04 开机自动运行应用程序
    Android中BindService方式使用的理解
  • 原文地址:https://www.cnblogs.com/sainsist/p/11670966.html
Copyright © 2011-2022 走看看