1. 程式人生 > 其它 >CodeForces 729 Div2

CodeForces 729 Div2

Odd Set

只有奇數和偶數相加才等於奇數,所以分別統計奇數和偶數的個數,相等輸出Yes,否則輸出No

#include <cstdio>
const int N = 205;
int n, a[N];
int main()
{
    int T; scanf("%d", &T);
    while (T--) {
        int cnt = 0, cnt2 = 0; scanf("%d", &n);
        for (int i = 1; i <= 2 * n; i++)
            scanf("%d", &a[i]);
        for (int i = 1; i <= 2 * n; i++) {
            if (a[i] & 1) cnt++;
            else cnt2++;
        }
        if (cnt == cnt2) puts("Yes");
        else puts("No");
    }
}

Plus and Multiply

滿足條件的\(n\)可以寫成\(a^x+by\)的形式,也就是說\(a^x\equiv n\pmod{b}\)

列舉\(x\)判斷即可

#include <cstdio>
#define ll long long
int main() 
{
	int T; scanf("%d", &T);
	while (T--) {
		ll n, a, b; scanf("%lld%lld%lld", &n, &a, &b);
		if (a == 1) { // 特判
			if (n % b == 1 || n == 1 || b == 1) puts("Yes");
			else puts("No");
			continue;
		}
		ll k = n % b; bool flag = false;
		for (ll i = 1; i <= n; i *= a) // 列舉a^x
		    if (i % b == k) {flag = true; break;}
		if (flag) puts("Yes");
		else puts("No");
	}
	return 0;
}

Strange Function

在題目中\(f(i)\)表示使得\(x\)不是\(i\)的因子的最小的正整數\(x\),即\(f(i)\)表示最小的一個正整數x滿足\(lcm(1, 2, ..., x-1)|i\)\(lcm(1,2,...,x) \nmid i\)

發現lcm的增長是非常快的,所以考慮將問題從原來的知道\(i\)列舉\(x\)轉化成知道\(x\)計算有多少個\(i\)符合條件。

順著這個思路往下想,滿足\(lcm(1, 2, ..., x-1)|i\)這個條件的 \(i∈[1~n]\)的個數有$ \left \lfloor \frac{n}{lcm(1,2,...,x-1)} \right \rfloor\(個,同理滿足\)

lcm(1,2,...,x) \nmid i$ 這個條件的有$ \left \lfloor \frac{n}{lcm(1,2,...,x)} \right \rfloor $個。

容斥原理, 同時滿足兩個條件的\(i\)的個數有 $ \left \lfloor \frac{n}{lcm(1,2,...,x-1)} \right \rfloor-\left \lfloor \frac{n}{lcm(1,2,...,x)} \right \rfloor $個。

最後統計答案就是$ \sum\limits_{lcm(1,2,...,x-1)\leq n}^{} i\times (\left \lfloor \frac{n}{lcm(1,2,...,x-1)} \right \rfloor-\left \lfloor \frac{n}{lcm(1,2,...,x)} \right \rfloor)$

#include <cstdio>
#define ll long long
const int mod = 1e9 + 7;
ll n, ans, lcm[50];
inline ll gcd(ll a, ll b) {
	return !b ? a : gcd(b, a % b);
}
int main()
{
	int T; scanf("%d", &T); 
    lcm[1] = 1;
	while (T--) {
		scanf("%lld", &n); ans = 0;
		for (int i = 2; ; i++) {
			lcm[i] = i / gcd(lcm[i - 1], i) * lcm[i - 1]; // 計算lcm 
			ans = (ans + i * (n / lcm[i - 1] - n / lcm[i])) % mod; // 容斥原理
            if (lcm[i] > n) break;
		}
		printf("%lld\n", ans);
	}
	return 0;
}

Priority Queue

題目本質上是在求對於每一個 \(+x\)對哪些子序列會有貢獻,然後求和統計(因為子序列有\(2^n\)個)

這顯然是一道DP題,假定找到了處於位置 \(t\)的一個\(+x\),設\(dp_{i,j}\)表示到第 \(i\)位為止,集合\(T\)中有\(j\)個數 \(\leq x\)的方案數,操作序列是\(a\)陣列。我們的目的是要讓我們選定的這個\(+x\) 到最後並對答案產生貢獻,我們分成以下幾種情況討論:

  • \(i<t\)的時候

    1. 如果第\(i\)位是\(-\),那麼有\(dp_{i,j}=dp_{i-1,j}+dp_{i-1,j+1}\) 。特別的,當\(j=0\) 時,需要在前面式子的基礎上再$+dp_{i-1,0} $

      因為會有兩種情況,一個是上一個狀態中沒有 \(+x\)了,讀題知道這種情況是直接忽略掉 \(-\) ,還有就是可能上一個狀態中有\(>x\) 的數,這種就是刪去了一個 \(>x\)的數,兩種情況的狀態都是\(dp_{i-1,j}\) ,因此要算兩次。

    2. 如果第\(i\)位是\(+x\) 並且\(x>a_t\),則選與不選都不會對\(j\)產生影響,\(dp_{i,j}=dp_{i-1,j}\times2\)

    3. \(x\geq a_t\),選了\(j\)就要增加\(1\),否則\(j\)不變。

  • \(i=t\)的時候

    根據我們給的定義,這裡是必選的\(dp_{i,j}=dp_{i-1,j}\)

  • \(i> t\) 的時候

    1. 如果第\(i\)位是\(-\) ,則不存在\(i<t\)時的特殊情況 ,因為這時侯\(a_t\) 已經在序列中了,再刪就把 \(a_t\)給刪了,所以只用算一次

    2. 如果第\(i\)位是 \(+x\),若\(x>=a_t\),則選與不選都不會對\(j\)產生影響,\(dp_{i,j}=dp_{i-1,j}\times2\)

    3. \(x>a_t\), 選了\(j\)就要增加\(1\), 否則\(j\)不變。

最後統計下答案

\(ans=\sum\limits_{t=1}^n\sum\limits_{i=1}^n dp_{n,i}\times a_t\)

#include <cstdio>
#include <iostream>
#include <cstring>
#define int long long
const int mod = 998244353, N = 505;
int n, m, dp[N][N], ans;
struct A{
	int x;
	bool plus; // 判斷是哪種操作 
}a[N];
signed main() 
{
	scanf("%lld", &n);
	for (int i = 1; i <= n; i++) {
		char ch; std::cin >> ch;
		if (ch == '+') {
			a[i].plus = true;
			scanf("%lld", &a[i].x);
		}
		else a[i].plus = false;
	}
	for (int t = 1; t <= n; t++) {
		if (a[t].plus) {	
			memset(dp, 0, sizeof(dp)); // 每一次dp都要清零 
			dp[0][0] = 1; // 初始狀態 
			for (int i = 1; i < t; i++) { // i<t的情況 
				if (!a[i].plus) { // 如果第i位是- 
					for (int j = 0; j <= n; j++) 
						dp[i][j] += dp[i - 1][j + 1], dp[i][j] %= mod; // 累加選的方案
					for (int j = 0; j <= n; j++) 
						dp[i][j] += dp[i - 1][j], dp[i][j] %= mod; // 累加不選的方案 
					dp[i][0] = dp[i][0] + dp[i - 1][0]; dp[i][0] %= mod; // 特殊情況
				}
                else { // 如果第i位是+x 
                    if (a[i].x > a[t].x) // 並且x>a[t]
                        for (int j = 0; j <= n; j++) 
                            dp[i][j] += dp[i - 1][j] * 2 % mod, dp[i][j] %= mod; // 選與不選均不會對j有影響 
                    else { // 並且x>=a[t]
                        for (int j = 0; j <= n; j++)
                            dp[i][j] += dp[i - 1][j] % mod, dp[i][j] %= mod; // 不選
                        for (int j = 1; j <= n; j++) 
                            dp[i][j] += dp[i - 1][j - 1] % mod, dp[i][j] %= mod; // 選 
                    }
                }
			}
			for (int j = 0; j <= n; j++) // i=t的情況 
				dp[t][j] = dp[t - 1][j];
			for (int i = t + 1; i <= n; i++) { // i>t的情況 
				if (!a[i].plus) { // 第i位是-
					for (int j = 0; j <= n; j++) 
						dp[i][j] += dp[i - 1][j], dp[i][j] %= mod; // 不選 
					for (int j = 0; j <= n; j++) 
						dp[i][j] += dp[i - 1][j + 1], dp[i][j] %= mod; // 選 
				}
                else { // 第i位是+x
                    if (a[i].x >= a[t].x) // 如果x>=a[t]
                        for (int j = 0; j <= n; j++) 
                            dp[i][j] += dp[i - 1][j] * 2 % mod, dp[i][j] %= mod; // 同上一種情況
                    else {
                        for (int j = 0; j <= n; j++)
                            dp[i][j] += dp[i - 1][j] % mod, dp[i][j] %= mod; // 同上一種情況
                        for (int j = 1; j <= n; j++) 
                            dp[i][j] += dp[i - 1][j - 1] % mod, dp[i][j] %= mod;
                    }
                }
			}
			int tmp = 0;
			for (int i = 0; i <= n; i++)  // 計算總的貢獻 
				tmp += (dp[n][i] * a[t].x) % mod, tmp %= mod;
			ans += tmp; ans %= mod;
		}
	}
	printf("%lld", ans);
    return 0;
}