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\(個,同理滿足\)
容斥原理, 同時滿足兩個條件的\(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\)的時候
-
如果第\(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}\) ,因此要算兩次。
-
如果第\(i\)位是\(+x\) 並且\(x>a_t\),則選與不選都不會對\(j\)產生影響,\(dp_{i,j}=dp_{i-1,j}\times2\)。
-
若\(x\geq a_t\),選了\(j\)就要增加\(1\),否則\(j\)不變。
-
-
當 \(i=t\)的時候
根據我們給的定義,這裡是必選的\(dp_{i,j}=dp_{i-1,j}\)。
-
當\(i> t\) 的時候
-
如果第\(i\)位是\(-\) ,則不存在\(i<t\)時的特殊情況 ,因為這時侯\(a_t\) 已經在序列中了,再刪就把 \(a_t\)給刪了,所以只用算一次
-
如果第\(i\)位是 \(+x\),若\(x>=a_t\),則選與不選都不會對\(j\)產生影響,\(dp_{i,j}=dp_{i-1,j}\times2\) 。
-
若 \(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;
}