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\)的时候
-
如果第\(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;
}

浙公网安备 33010602011771号