Codeforces Round #729 (Div. 2) (A - E)

A. Odd Set

水题 看奇数个数是否为n

代码

#include 

using namespace std;

int n, sum;

void solve()
{
    cin >> n; sum = 0;
    for (int i = 1; i <= n * 2; i ++ )
    {
        int a; cin >> a;
        if (a & 1) sum ++ ;
    }
    if (sum == n) puts("YES");
    else puts("NO");
}

int main()
{
    int t;
    cin >> t;

    while (t -- )
    {
        solve();
    }

    return 0;
}

B. Plus and Multiply

给定一个a和一个b 对于一个一定包含1的集合 (假如x在这个集合 那么 x * a 和 x + b 也一定在这个集合中) 给定一个n 问n是否在此集合中
我们可以将在集合中的数变为 a x a^x ax + y * b 所以遍历i直到 a i a^i ai大于n 每次看看是否可以%b==0 如果可以就yes

代码

#include 

using namespace std;

typedef long long ll;

void solve()
{
    ll n, a, b;
    cin >> n >> a >> b;

    if (a == 1 || b == 1)
    {
        if ((n - 1) % b) puts("NO");
        else puts("YES");
        return;
    }

    ll res = 1;
    while (res <= n)
    {
        if ((n - res) % b == 0)
        {
            puts("YES");
            return;
        }
        res *= a;
    }
    puts("NO");
}

int main()
{
    int t;
    cin >> t;

    while (t -- )
    {
        solve();
    }

    return 0;
}

C. Strange Function

用 f(i) 表示最小的x i 无法被 x 整除 给定一个n 求 f(1) + … + f(n) 的sum值
我们可以这样想 lcm( a 1 , a 2 , . . . , a n a_{1}, a_{2}, ... ,a_{n} a1,a2,...,an) 是可以分别被 a 1 , a 2 , . . . , a n a_{1}, a_{2}, ..., a_{n} a1,a2,...,an整除的 我们可以i从小到大遍历 求1~i 的lcm 看看n中有多少数字能整除此时的lcm 即这些可以整除的数要往后推一位 初始化所有 f(i) 为1

代码

#include 

using namespace std;

typedef long long ll;

const ll P = 1e9 + 7;

ll gcd(ll a, ll b)
{
    return b ? gcd(b, a % b) : a;
}

ll lcm(ll a, ll b)
{
    return a / gcd(a, b) * b;
}

void solve()
{
    ll n; cin >> n;
    ll ans = n, lc = 1;
    for (int i = 2; lc <= n; i ++ )
    {
        (ans += (n / lc)) %= P;
        lc = lcm(lc, i);
    }
    cout << ans << endl;
}

int main()
{
    int t;
    cin >> t;

    while (t -- )
    {
        solve();
    }

    return 0;
}

D. Priority Queue

一个计数dp 还挺难思考的 我们用 d p i , j dp_{i,j} dpi,j表示从1到 i 中有 j 个数小于 a k a_{k} ak 这样的方案数
因为n不大 所以我们可以直接遍历 这样的时间复杂度为 O( n 3 n^{3} n3) 这样分类来看 我们可以把所有的 - 都看为 a i a_{i} ai = -1
对于每一个 d p i , j dp_{i,j} dpi,j都是从 d p i − 1 , j dp_{i-1,j} dpi1,j转移过来的 (即当前集合不选择 a i a_{i} ai)
a i a_{i} ai = -1的时候 我们选择拿这个 就有了 d p i , j dp_{i,j} dpi,j += d p i − 1 , j + 1 dp_{i-1,j+1} dpi1,j+1 以及 += d p i − 1 , j dp_{i-1,j} dpi1,j 后者是在 j = 0 的时候才加的一种方案 弹出一个大的数依然是 d p i − 1 , j dp_{i-1,j} dpi1,j
如果 a i a_{i} ai != -1 我们可以通过比大小
如果 a i a_{i} ai > a k a_{k} ak || a i a_{i} ai= a k a_{k} ak && i > k 则 d p i , j dp_{i,j} dpi,j += d p i − 1 , j dp_{i-1,j} dpi1,j
如果 a i a_{i} ai < a k a_{k} ak || a i a_{i} ai= a k a_{k} ak && i < k 则 d p i , j dp_{i,j} dpi,j += d p i − 1 , j − 1 dp_{i-1,j-1} dpi1,j1
每次维护一下ans即可

代码

#include 

using namespace std;

typedef long long ll;

const int N = 510, P = 998244353;

int n;
ll dp[N][N], a[N], ans;

void solve()
{
    cin >> n;
    for (int i = 1; i <= n; i ++ )
    {
        char c; cin >> c;
        if (c == '-') a[i] = -1;
        else cin >> a[i];
    }

    for (int i = 1; i <= n; i ++ )
    {
        if (a[i] == -1) continue;
        memset(dp, 0, sizeof dp); 
        dp[0][0] = 1;
        for (int j = 1; j <= n; j ++ )
            for (int k = 0; k <= j; k ++ )
            {
                (dp[j][k] += dp[j - 1][k]) %= P;
                if (a[j] == -1)
                {
                    (dp[j][k] += dp[j - 1][k + 1]) %= P;
                    if (k == 0 && j < i) (dp[j][k] += dp[j - 1][k]) %= P;
                }
                else
                {
                    if (i == j) continue;
                    if (a[j] < a[i] || a[j] == a[i] && j < i) 
                    {
                        if (k != 0)
                            (dp[j][k] += dp[j - 1][k - 1]) %= P;
                    }
                    else (dp[j][k] += dp[j - 1][k]) %= P;
                }
            }
        for (int j = 0; j <= n; j ++ )
            (ans += dp[n][j] * a[i]) %= P;
    }
    cout << ans << endl;
}

int main()
{
    cin.tie(0);
    ios::sync_with_stdio(false);

    solve();

    return 0;
}

你可能感兴趣的:(Codeforces,算法)