zoukankan      html  css  js  c++  java
  • 【ATcoder】AtCoder Beginner Contest 159 题解

    官方题解

    落谷链接

    ATC链接

    A - The Number of Even Pairs

    题意

    给你两个数$n, m$代表有$n$个偶数,$m$个奇数。让你输出$n$个偶数$m$个奇数从中任选两个数(没有顺序)相加结果为偶数的个数。

    题解

    相加为偶数只有偶加偶和奇加奇两种情况,其实就是在$n$个数中取两个($Cinom{2}{n}$),在$m$个数中取两个($Cinom{2}{m}$)。

    时间复杂度$O(1)$

    1 #include <iostream>
    2 using namespace std;
    3 int main() {
    4     long long n, m;
    5     cin >> n >> m;
    6     cout << n * (n - 1) / 2 + m * (m - 1) / 2;
    7     return 0;
    8 }
    A - The Number of Even Pairs

    B - String Palindrome

    题意

    定义一个字符串 $S$ 是强回文串当且仅当 $S$,$S_{1...frac{(|s|+1)}{2}}$ 和 $S_{|s|-frac{(|s|+3)}{2}+1...|s|}$都是回文的。判断一个回文串是不是强回文串。$3 leq |s| leq 99$且$|s|$是奇数。

    题解

    直接取出每一部分的字符串,判断到中心距离相等的位置的字符是否相等即可。

    时间复杂度$O(|s|)$。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 using namespace std;
     5 char s[100], tmp[100];
     6 int top;
     7 int n, nn;
     8 int main() {
     9     scanf("%s", s + 1);
    10     n = strlen(s + 1);
    11     nn = n;
    12     for (int i = 1; i <= nn; i++) {
    13         if (s[i] != s[nn - i + 1]) {
    14             puts("No");
    15             return 0;
    16         }
    17     }
    18     nn = (n - 1) / 2;
    19     for (int i = 1; i <= nn; i++) {
    20         if (s[i] != s[nn - i + 1]) {
    21             puts("No");
    22             return 0;
    23         }
    24     }
    25     nn = (n + 3) / 2;
    26     for (int i = nn; i <= n; i++) {
    27         tmp[++top] = s[i];
    28     }
    29     for (int i = 1; i <= top; i++) {
    30         if (tmp[i] != tmp[top - i + 1]) {
    31             puts("No");
    32             return 0;
    33         }
    34     }
    35     puts("Yes");
    36     return 0;
    37 }
    B - String Palindrome

    C - Maximum Volume

    题意

    给定一个整数x。求所有各棱长为实数且和为x的长方体中最大的体积是多少。

    题解

    小学奥数题...

    和一定差小积大。

    其实就是一个均值不等式

    设棱长为$a,b,c$,则 $a imes b imes c leq frac{(a+b+c)^3}{27}=frac{x^3}{27}$,当$a=b=c$时成立。

     1 #include <iostream>
     2 #include <cstdio>
     3 using namespace std;
     4 double l;
     5 int main() {
     6     scanf("%lf", &l);
     7     l = l / 3;
     8     printf("%.12lf", l * l * l);
     9     return 0;
    10 }
    C - Maximum Volume

     D - Banned K

    题意

    我们有n个数,每个数都在[1,n]中,如果去掉第k个数,问剩下的数有多少对相同的数(不计顺序),$1 leq n leq 2 imes 10^5$。

    题解

    我们可以把 $n$ 个数中有多少相同的数对,因为每个数都很小所以这点我们可以用堆来做。

    设 $cnt[i]$ 代表 $i$ 这个数出现的次数所以答案等于 $sum_{i=1}^{n}frac{cnt[i] imes (cnt[i]-1)}{2}$。

    现在我们来看删掉一个值为 $x$ 的数。

    $cnt[x]$ 的值减小了一,它的贡献变成了 $frac{(cnt[x]-1) imes (cnt[x]-2)}{2}$,相比之前减少了 $cnt[x]-1$。

    设不删时的答案是 $tot$,则删掉一个权值为 $x$ 的数的答案为 $tot-(cnt[x]-1)$。

    单词询问复杂度O(1)。

     1 //这里sum就是cnt
     2 #include <iostream>
     3 #include <cstdio>
     4 using namespace std;
     5 const int N = 2e5 + 10;
     6 int n, a[N];
     7 long long sum[N], tot;
     8 int main() {
     9     scanf("%d", &n);
    10     for (int i = 1; i <= n; i++) scanf("%d", &a[i]), sum[a[i]]++;
    11     for (int i = 1; i <= n; i++) {
    12         tot += sum[i] * (sum[i] - 1) / 2;
    13     }
    14     for (int i = 1; i <= n; i++) {
    15         printf("%lld
    ", tot - (sum[a[i]] - 1));
    16     }
    17     return 0;
    18 }
    D - Banned K

    E - Dividing Chocolate

    我太弱了,我比赛时这题竟然都没调出来。

    题意

    有一个$n imes m$的矩阵,每个位置要不是要不不是零,用尽量少的次数把这个矩阵切成几块(只能把整行或整列与下一行或列切开,具体可看下面的例子)使得每一块中1的个数少于某个常数。

    $1 leq n leq 10, 1 leq m leq 1000$

    题解

    我们发现n非常的小,于是我们可以枚举行之间且的情况,再判断列之间要切的情况,取最小值即可。

    时间复杂度$O(2^n imes n imes m)$

    下面代码是E - Dividing Chocolate

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring> 
     4 using namespace std;
     5 int n, m, k;
     6 int cnt[15][1005];
     7 char mp[15][1005];
     8 bool vis[1005];
     9 int cut[20], top;
    10 int ans = 0x7f7f7f7f;
    11 int cal(int x1, int x2, int y1, int y2) {
    12     return cnt[x2][y2] - cnt[x2][y1 - 1] - cnt[x1 - 1][y2] + cnt[x1 - 1][y1 - 1];
    13 }
    14 void dfs(int pos) {
    15     cut[++top] = pos;
    16     if (pos == n) {
    17         memset(vis, 0, sizeof(vis)); 
    18         int sx, sy, lst = 0, tmp = 0;
    19         for (int j = 1; j <= m; j++) {
    20             for (int i = 1; i <= top; i++) {
    21                 sx = cut[i - 1] + 1, sy = lst + 1;
    22                 if (cal(sx, cut[i], sy, j) > k) {
    23                     if (lst == j - 1) {
    24                         top--;
    25                         return;
    26                     } else {
    27                         sy = j;
    28                         if (!vis[j - 1]) tmp++, vis[j - 1] = 1;
    29                     }
    30                 }
    31             }
    32             if (vis[j - 1]) lst = j - 1;
    33         }
    34         ans = min(ans, tmp + top - 1);
    35         top--;
    36         return;
    37     }
    38     for (int i = pos + 1; i <= n; i++) {
    39         dfs(i);
    40     }
    41     top--;
    42 }
    43 int main() {
    44     scanf("%d%d%d", &n, &m, &k);
    45     for (int i = 1; i <= n; i++) {
    46         scanf("%s", mp[i] + 1); 
    47         for (int j = 1; j <= m; j++) {
    48             cnt[i][j] = cnt[i - 1][j] + cnt[i][j - 1] - cnt[i - 1][j - 1] + mp[i][j] - '0';
    49         }
    50     }
    51     for (int i = 1; i <= n; i++) {
    52         dfs(i);
    53     }
    54     cout << ans;
    55     return 0;
    56 }
    F - Knapsack for All Segments

    F - Knapsack for All Segments

    题意

    一个长度为n的数组,求任意[ L,R ]区间子序列和为S的总数的和。

    题解

    看到和为s,很容易想到背包,其实这就是一道01背包的变形。

    考虑一组和为s的排列x1<x2<...<xk,所有[1,x1]内的L,[xk, n]之内的R都包含这组排列,所以它的贡献就是$x_1 imes (n-x_k+1)$。

    设dp[i][j]表示枚举到第i个数,和为j的排列的第一个数的和。

    显然dp[0][j]都是0。转移方程类似01背包,dp[i][j]=dp[i-1][j]+(j==a[i]?i:0)。

    考虑如何统计答案,如果a[i]=s,ans+=i*(n-i+1);如果a[i]>s,ans+=dp[s-a[i]]*(n-i+1)。如果a[i]<s则不用更新。

    当然类似于背包问题,这题也可以用滚动背包优化空间复杂度。

    时间复杂度O(ns);空间复杂度O(n+s)

     1 #include <iostream>
     2 #include <cstdio>
     3 using namespace std;
     4 const long long N = 3010;
     5 const long long S = 3010;
     6 const long long mod = 998244353;
     7 long long n, s;
     8 long long a[N];
     9 long long dp[S];
    10 long long ans;
    11 int main() {
    12     scanf("%lld%lld", &n, &s);
    13     for (long long i = 1; i <= n; i++) scanf("%lld", &a[i]);
    14     for (long long i = 1; i <= n; i++) {
    15         if (s == a[i]) {
    16             ans += i * (n - i + 1) % mod;
    17             ans %= mod;
    18         } else if (s > a[i]) {
    19             ans += dp[s - a[i]] * (n - i + 1) % mod;
    20             ans %= mod;
    21         }
    22         for (long long j = s; j >= a[i]; j--) {
    23             dp[j] += (dp[j - a[i]] + (j == a[i] ? i : 0)) % mod;
    24             dp[j] %= mod;
    25         }
    26     } 
    27     printf("%lld", ans);
    28     return 0;
    29 }
    F - Knapsack for All Segments
  • 相关阅读:
    739. Daily Temperatures
    556. Next Greater Element III
    1078. Occurrences After Bigram
    1053. Previous Permutation With One Swap
    565. Array Nesting
    1052. Grumpy Bookstore Owner
    1051. Height Checker
    数据库入门及SQL基本语法
    ISCSI的概念
    配置一个IP SAN 存储服务器
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/12550421.html
Copyright © 2011-2022 走看看