A – Even Substrings
很简单,扫描的时候如果所在数位为偶数位,向答案添加当前数位即可。
scanf("%d", &len), scanf("%s", str + 1);
for (int i = 1; i <= len; i++)
if (((str[i] - '0') & 1) == 0)
// A.cpp
#include <bits/stdc++.h>
using namespace std;
char str[66000];
int main()
{
int ans = 0, len;
scanf("%d", &len), scanf("%s", str + 1);
for (int i = 1; i <= len; i++)
if (((str[i] - '0') & 1) == 0)
ans += i;
printf("%d", ans);
return 0;
}
// A.cpp
#include <bits/stdc++.h>
using namespace std;
char str[66000];
int main()
{
int ans = 0, len;
scanf("%d", &len), scanf("%s", str + 1);
for (int i = 1; i <= len; i++)
if (((str[i] - '0') & 1) == 0)
ans += i;
printf("%d", ans);
return 0;
}
B – Chocolates
从后面往前扫描,取上一个值减一和限制的最小值即可(记得特判\(0\)的情况)。
const int MAX_N = (int)2e5 + 2000;
int n, arr[MAX_N], trial[MAX_N];
memset(trial, 0x3f, sizeof(trial));
for (int i = n; i >= 1; i--)
trial[i] = min(trial[i + 1] - 1, arr[i]);
for (int i = 1; i <= n; i++)
scanf("%d", &arr[i]), r += arr[i];
// B.cpp
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAX_N = (int)2e5 + 2000;
int n, arr[MAX_N], trial[MAX_N];
ll check()
{
memset(trial, 0x3f, sizeof(trial));
ll acc = 0;
for (int i = n; i >= 1; i--)
{
if (trial[i + 1] == 0)
{
trial[i] = 0;
continue;
}
trial[i] = min(trial[i + 1] - 1, arr[i]);
acc += trial[i];
}
return acc;
}
int main()
{
ll l = 0, r = 0;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &arr[i]), r += arr[i];
printf("%lld", check());
return 0;
}
// B.cpp
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAX_N = (int)2e5 + 2000;
int n, arr[MAX_N], trial[MAX_N];
ll check()
{
memset(trial, 0x3f, sizeof(trial));
ll acc = 0;
for (int i = n; i >= 1; i--)
{
if (trial[i + 1] == 0)
{
trial[i] = 0;
continue;
}
trial[i] = min(trial[i + 1] - 1, arr[i]);
acc += trial[i];
}
return acc;
}
int main()
{
ll l = 0, r = 0;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &arr[i]), r += arr[i];
printf("%lld", check());
return 0;
}
C – Edgy Trees
乍一看很难的题,其实很水。
考虑直接容斥掉,初始答案为\(n^k\),在建树的时候忽略掉黑边,然后对于每一个连通块计算出贡献\(subtreeSiz^k\),记得这个贡献是负的:
\[ans = n^k – \sum_{t \in subtree} t.size()^k\]
const int MAX_N = 1e5 + 2000, mod = 1e9 + 7;
int head[MAX_N], current, n, tmpx, tmpy, tmpz;
int subtreeSiz[MAX_N], totTree, k;
void addpath(int src, int dst, int color)
edges[current].to = dst, edges[current].nxt = head[src];
edges[current].color = color, head[src] = current++;
ll quick_pow(ll bas, ll tim)
void dfs(int u, int org, int fa)
for (int i = head[u]; i != -1; i = edges[i].nxt)
dfs(edges[i].to, org, u);
memset(head, -1, sizeof(head));
for (int i = 1; i <= n - 1; i++)
scanf("%d%d%d", &tmpx, &tmpy, &tmpz);
addpath(tmpx, tmpy, tmpz), addpath(tmpy, tmpx, tmpz);
for (int i = 1; i <= n; i++)
ll ans = quick_pow(n, k);
for (int i = 1; i <= totTree; i++)
ans = (ans - quick_pow(subtreeSiz[i], k) + mod) % mod;
// C.cpp
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAX_N = 1e5 + 2000, mod = 1e9 + 7;
int head[MAX_N], current, n, tmpx, tmpy, tmpz;
int subtreeSiz[MAX_N], totTree, k;
bool vis[MAX_N];
struct edge
{
int to, nxt, color;
} edges[MAX_N];
void addpath(int src, int dst, int color)
{
edges[current].to = dst, edges[current].nxt = head[src];
edges[current].color = color, head[src] = current++;
}
ll quick_pow(ll bas, ll tim)
{
if (bas == 1)
return 1;
ll ans = 1;
while (tim)
{
if (tim & 1)
ans = ans * bas % mod;
bas = bas * bas % mod;
tim >>= 1;
}
return ans;
}
void dfs(int u, int org, int fa)
{
vis[u] = true;
subtreeSiz[org]++;
for (int i = head[u]; i != -1; i = edges[i].nxt)
if (edges[i].to != fa)
dfs(edges[i].to, org, u);
}
int main()
{
memset(head, -1, sizeof(head));
scanf("%d%d", &n, &k);
bool flag = false;
for (int i = 1; i <= n - 1; i++)
{
scanf("%d%d%d", &tmpx, &tmpy, &tmpz);
if (tmpz != 1)
addpath(tmpx, tmpy, tmpz), addpath(tmpy, tmpx, tmpz);
else
flag = true;
}
if (!flag)
printf("0"), exit(0);
for (int i = 1; i <= n; i++)
if (!vis[i])
dfs(i, ++totTree, 0);
ll ans = quick_pow(n, k);
for (int i = 1; i <= totTree; i++)
ans = (ans - quick_pow(subtreeSiz[i], k) + mod) % mod;
printf("%lld", ans);
return 0;
}
// C.cpp
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAX_N = 1e5 + 2000, mod = 1e9 + 7;
int head[MAX_N], current, n, tmpx, tmpy, tmpz;
int subtreeSiz[MAX_N], totTree, k;
bool vis[MAX_N];
struct edge
{
int to, nxt, color;
} edges[MAX_N];
void addpath(int src, int dst, int color)
{
edges[current].to = dst, edges[current].nxt = head[src];
edges[current].color = color, head[src] = current++;
}
ll quick_pow(ll bas, ll tim)
{
if (bas == 1)
return 1;
ll ans = 1;
while (tim)
{
if (tim & 1)
ans = ans * bas % mod;
bas = bas * bas % mod;
tim >>= 1;
}
return ans;
}
void dfs(int u, int org, int fa)
{
vis[u] = true;
subtreeSiz[org]++;
for (int i = head[u]; i != -1; i = edges[i].nxt)
if (edges[i].to != fa)
dfs(edges[i].to, org, u);
}
int main()
{
memset(head, -1, sizeof(head));
scanf("%d%d", &n, &k);
bool flag = false;
for (int i = 1; i <= n - 1; i++)
{
scanf("%d%d%d", &tmpx, &tmpy, &tmpz);
if (tmpz != 1)
addpath(tmpx, tmpy, tmpz), addpath(tmpy, tmpx, tmpz);
else
flag = true;
}
if (!flag)
printf("0"), exit(0);
for (int i = 1; i <= n; i++)
if (!vis[i])
dfs(i, ++totTree, 0);
ll ans = quick_pow(n, k);
for (int i = 1; i <= totTree; i++)
ans = (ans - quick_pow(subtreeSiz[i], k) + mod) % mod;
printf("%lld", ans);
return 0;
}
D – Steps to One
参考了这位巨佬的文章:cf1139D. Steps to One(dp)
首先考虑设计状态,设\(dp[i]\)为当\(gcd\)为\(i\)时将整个序列的\(gcd\)变成\(1\)的期望长度。这个状态可以搞出:
\[ dp[i] = \frac{ \sum_{j = 1}^i dp[gcd(i,j)]+1 }{m} \]
然后我们可以枚举\(k=gcd(i,j)\):
\[ dp[i] = 1 + \frac{ \sum_{k = 1}^m dp[k]*f(i,k) }{m} \]
其中\(f(i,k)\)代表在\(j \in [1,m]\)区间内满足\(gcd(i,j)=k\)的\(j\)的个数,我们可以考虑进行预处理。注意到枚举时可能会枚举到\(i\)自己,所以提出来:
\[ (1-\frac{\lfloor \frac{m}{i} \rfloor}{m})dp[i] = 1 + \frac{\sum_{k=1}^{i-1} dp[k]*f(i,k)}{m} \]
我们现在来思考如何预处理\(f\)函数。首先,我们可以把初值都设置为\(f(i,k) = \lfloor \frac{m}{k} \rfloor\),然后对于\(u>v,v|u\)的数对,\(f(i,v)-=f(i,u)\)进行容斥即可。
const int MAX_N = 1e5 + 200, mod = 1e9 + 7;
vector<int> facts[MAX_N], cnt[MAX_N];
ll quick_pow(ll bas, ll tim)
scanf("%lld", &m), invm = quick_pow(m, mod - 2);
for (int i = 1; i <= m; i++)
for (int j = i; j <= m; j += i)
for (int i = 1; i <= m; i++)
cnt[i].resize(facts[i].size() + 1);
for (int j = facts[i].size() - 1; j != -1; j--)
cnt[i][j] = m / facts[i][j];
int siz = facts[i].size();
for (int k = j + 1; k < siz; k++)
if (facts[i][k] % facts[i][j] == 0)
for (int i = 2; i <= m; i++)
for (int j = 0; j < facts[i].size(); j++)
tmp = (tmp + cnt[i][j] * dp[facts[i][j]] + mod) % mod;
dp[i] = (tmp + m + mod) % mod * quick_pow(dom, mod - 2) % mod;
for (int i = 1; i <= m; i++)
ans = (ans + dp[i] + 1 + mod) % mod;
printf("%lld", ans * invm % mod);
// D.cpp
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAX_N = 1e5 + 200, mod = 1e9 + 7;
vector<int> facts[MAX_N], cnt[MAX_N];
ll m, dp[MAX_N], invm;
ll quick_pow(ll bas, ll tim)
{
ll ans = 1;
while (tim)
{
if (tim & 1)
ans = ans * bas % mod;
bas = bas * bas % mod;
tim >>= 1;
}
return ans;
}
int main()
{
scanf("%lld", &m), invm = quick_pow(m, mod - 2);
for (int i = 1; i <= m; i++)
for (int j = i; j <= m; j += i)
facts[j].push_back(i);
for (int i = 1; i <= m; i++)
{
cnt[i].resize(facts[i].size() + 1);
for (int j = facts[i].size() - 1; j != -1; j--)
{
cnt[i][j] = m / facts[i][j];
int siz = facts[i].size();
for (int k = j + 1; k < siz; k++)
if (facts[i][k] % facts[i][j] == 0)
cnt[i][j] -= cnt[i][k];
}
}
ll ans = 0;
for (int i = 2; i <= m; i++)
{
int dom = m, tmp = 0;
for (int j = 0; j < facts[i].size(); j++)
if (facts[i][j] == i)
dom -= cnt[i][j];
else
tmp = (tmp + cnt[i][j] * dp[facts[i][j]] + mod) % mod;
dp[i] = (tmp + m + mod) % mod * quick_pow(dom, mod - 2) % mod;
}
for (int i = 1; i <= m; i++)
ans = (ans + dp[i] + 1 + mod) % mod;
printf("%lld", ans * invm % mod);
return 0;
}
// D.cpp
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAX_N = 1e5 + 200, mod = 1e9 + 7;
vector<int> facts[MAX_N], cnt[MAX_N];
ll m, dp[MAX_N], invm;
ll quick_pow(ll bas, ll tim)
{
ll ans = 1;
while (tim)
{
if (tim & 1)
ans = ans * bas % mod;
bas = bas * bas % mod;
tim >>= 1;
}
return ans;
}
int main()
{
scanf("%lld", &m), invm = quick_pow(m, mod - 2);
for (int i = 1; i <= m; i++)
for (int j = i; j <= m; j += i)
facts[j].push_back(i);
for (int i = 1; i <= m; i++)
{
cnt[i].resize(facts[i].size() + 1);
for (int j = facts[i].size() - 1; j != -1; j--)
{
cnt[i][j] = m / facts[i][j];
int siz = facts[i].size();
for (int k = j + 1; k < siz; k++)
if (facts[i][k] % facts[i][j] == 0)
cnt[i][j] -= cnt[i][k];
}
}
ll ans = 0;
for (int i = 2; i <= m; i++)
{
int dom = m, tmp = 0;
for (int j = 0; j < facts[i].size(); j++)
if (facts[i][j] == i)
dom -= cnt[i][j];
else
tmp = (tmp + cnt[i][j] * dp[facts[i][j]] + mod) % mod;
dp[i] = (tmp + m + mod) % mod * quick_pow(dom, mod - 2) % mod;
}
for (int i = 1; i <= m; i++)
ans = (ans + dp[i] + 1 + mod) % mod;
printf("%lld", ans * invm % mod);
return 0;
}