Loading [MathJax]/extensions/tex2jax.js

Codeforces Round #548 (Div. 2) 解题报告 (CF1139)

A – Even Substrings

很简单,扫描的时候如果所在数位为偶数位,向答案添加当前数位即可。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// 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; }
// 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\)的情况)。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// 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; }
// 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\]

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// 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; }
// 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)\)进行容斥即可。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// 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; }
// 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;
}

Leave a Reply

Your email address will not be published. Required fields are marked *