Codeforces Round #723 (Div. 2) 题解A-C2

A. Mean Inequality

分析:很简单的构造。
代码:

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 100;
int a[N], b[N];
int main()
{
    int t; cin >> t;
    while(t--)
    {
        int n; cin >> n;
        for(int i = 1; i <= n<<1; i++) cin >> a[i];
        sort(a+1,a+1+2*n);
        for(int i = 1; i <= 2*n; i++)
        {
            if(i&1) b[i] = a[(i+1)>>1];
            else b[i] = a[n+(i>>1)];
        }
        for(int i = 1; i <= 2*n; i++) cout << b[i] << " ";
        cout << endl;
    }
//     system("pause");
}

B. I Hate 1111

分析:
显然大于111的形如 [ 1 ∗ ] [1^*] [1∗]的数字都可以被 11 a + 111 b 11a+111b 11a+111b来表示, 其中a和b是常数. 所以我们只要分析给定的数字n可不可以被11和111分解即可.
考虑 111 % 11 = 1 111\%11=1 111%11=1, 不难发现任何可以被11和111分解的数字, 可以被分解成 11 a + 111 b 11a+111b 11a+111b, 其中 b ≤ 10 b\le10 b≤10. 那么枚举b即可.
代码:

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long INT;

int main()
{
    int t; cin >> t;
    while(t--)
    {
        INT n; cin >> n;
        bool f = 0;
        int x = n%11;
        if((n -= x*111) >= 0) 
            if(n%11 == 0) f = 1;
        // printf("= %d*111 + %d*11\n",x,n/11);
        if(f) cout << "YES\n";
        else cout << "NO\n";
    }
    // system("pause");
}

C1. Potions (Easy Version)

分析:
因为是简单版本,所以下面给出 O ( n 2 ) O(n^2) O(n2)的做法.
参考最长上升子序列的DP方式, d p [ i ] dp[i] dp[i]表示长度为 i i i的合法子序列中最大的sum.
状态转移方程: d p [ i ] = d p [ i − 1 ] + a [ i ] dp[i] = dp[i-1] + a[i] dp[i]=dp[i−1]+a[i]
ps: 记得开long long
代码:

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long INT;
const int N = 3000;

INT a[N], f[N];

int main()
{
    int n; cin >> n;
    for(int i = 0; i < n; i++) cin >> a[i];
    int start = 0;
    while(start < n && a[start]<0) start++;
    if(start == n) 
    {
        cout << 0 << endl;
        // system("pause");
        return 0;
    }
    f[1] = a[start];
    int maxh = 1;
    for(int i = start+1; i < n; i++)
    {
        for(int j = maxh; j >= 0; j--)
        {
            if(f[j] + a[i] >= 0)
            {
                f[j+1] = max(f[j+1], f[j]+a[i]);
                if(j == maxh)
                {
                    maxh++;
                }
            }
        }
    }
    cout << maxh << endl;
    // system("pause");
}

C2. Potions (Hard Version)

分析:
下面介绍 O ( n log ⁡ n ) O(n \log n) O(nlogn)的做法.
算法 tag: 反悔贪心.
我们维护一个反悔堆, 这将是一个小根堆(优先队列).
每当我们把一个负数加入我们的子序列时, 我们就把负数压入堆中.
原因是, 我们将负数加入子序列(当前最优解)的时候是最优, 但是在未来我们可能可以遇到更好的负数(本质上就是数值比当前这个负数大), 因此我们需要提供一个反悔机制.
当我们的子序列无法加入当前的负数的时候, 一般来说是因为子序列的sum+当前的负数<0. 如果此时堆顶元素小于当前负数, 那么选择当前负数而不选择堆顶负数是一定更优的, 那么就弹出堆顶元素, 压入当前负数.
具体操作看代码:

#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
priority_queue<long long, vector<long long>, greater<long long>> h;
long long sum;
int cnt;
int main()
{
    int n; scanf("%d",&n);
    for(int i = 0; i < n; i++) 
    {
        long long tmp; scanf("%lld",&tmp);
        if(tmp >= 0) sum += tmp, cnt++;
        else if(tmp + sum >= 0) 
        {
            sum += tmp;
            cnt++;
            h.push(tmp);
        }
        else if(h.size() && h.top() < tmp)
        {
            sum = sum - h.top() + tmp;
            h.pop();
            h.push(tmp);
        }
    }
    printf("%d\n",cnt);
    // system("pause");
}
上一篇:111


下一篇:题1 111%13的运算结果