Codeforces Round #553 (Div. 2)/codeforces1151

CodeForces1151

Maxim and Biology

解析:

题目大意

每次可以使原串中的一个字符\(+1/-1\)\(Z + 1\to A, A -1\to Z\),求至少修改多少次可以使 ACTG 是原串的子串

\(4\le |S|\le 50\)


思路:

直接暴力尝试每个子串。


code

#include <bits/stdc++.h>
const int N = 50 + 10;
const int INF = 0x3f3f3f3f;
using namespace std;
int n, ans;
char s[N];
signed main()
{
    scanf ("%d%s", &n, s + 1); ans = INF;
    for (int i = 1; i <= n - 3; i++)
    {
        ans = min (ans, min (abs(s[i] - 'A'), 26 - abs((s[i] - 'A'))) +
                        min (abs(s[i + 1] - 'C'), 26 - abs((s[i + 1] - 'C'))) +
                        min (abs(s[i + 2] - 'T'), 26 - abs((s[i + 2] - 'T'))) +
                        min (abs(s[i + 3] - 'G'), 26 - abs((s[i + 3] - 'G'))));
    }
    printf ("%d\n", ans);
    return 0;
}

Dima and a Bad XOR

解析:

题目大意:

给你一个大小为 \(n \times m\) 的矩阵,其中只包含非负整数。你需要从矩阵的每一行中选出一个整数,使得所选整数的按位异或严格大于零。

输出 \(n\) 行,每行一个正整数表示选择选当前第几个数。


思路:

考虑异或和大于零的充要条件是某一位不为零,那么可以拆位考虑。现在问题变成了给你一个0/1矩阵,让你在每行选一个数使最终异或和为1。

根据异或的性质可以发现选 0 不会影响异或结果,所以我们只需要找出来奇数个1即可。

我们先判断所有行中有 1 的行的个数,如果为奇数那每行都选 1 即可。如果个数为偶数那就找一个既有 0 也有 1 的行强行选 0 即可。


code:

#include <bits/stdc++.h>
using namespace std;
const int N = 500 + 10;
inline int read ()
{
    int x = 0, f = 1;
    char ch = getchar ();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar (); }
    while (ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar (); }
    return x * f;
}
int n, m;
int a[N][N];
void solve (int x, int d)
{
    printf ("TAK\n");
    for (int i = 1; i <= n; i++)
    {
        bool flag2 = false;
        if (x != i)
        {
            for (int j = 1; j <= m; j++)
                if ((a[i][j] >> d) & 1) { printf ("%d ", j); flag2 = true; break; }
        }
        else
        {
            for (int j = 1; j <= m; j++)
                if (!((a[i][j] >> d) & 1)) { printf ("%d ", j); flag2 = true; break; }
        }
        if (!flag2) printf ("1 ");
    }
}
signed main()
{
    n = read (), m = read ();
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++) a[i][j] = read ();
    for (int d = 10; d >= 0; d--)
    {
        int cnt = 0;
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++)
                if ((a[i][j] >> d) & 1) { cnt++; break; }
        if (cnt & 1) { solve (0, d); return 0; }
        else
        {
            for (int i = 1; i <= n; i++)
            {
                int cnt2 = 0;
                for (int j = 1; j <= m; j++)
                    if ((a[i][j] >> d) & 1) cnt2++;
                if (cnt2 && cnt2 < m) { solve (i, d);  return 0; }
            }
        }
    }
    printf ("NIE\n");
    return 0;
}

Problem for Nazar

解析:

题目大意

\(i\)为奇数时,从集合\(\mathrm{A}\)中依次取数(取过了),当\(i\)为偶数时,从集合\(\mathrm{B}\)中向后取数。求黑板上第\(l\)个数到第\(r\)个数的和,答案对 \(10^9+7\)取余。

\(1 \le l,r \le 10^{18}\)


思路:

考虑把询问的区间按照奇数和偶数分成若干段,最多有 \(\log 10^{18}\) 个段,于是直接暴力即可。


code

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 10;
const int INV = 500000004;
const int mods = 1e9 + 7;
typedef pair <int, int> pii;
inline int read ()
{
    int x = 0, f = 1;
    char ch = getchar ();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar (); }
    while (ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar (); }
    return x * f;
}
int l, r;
int sum1, sum2;
int ans;
signed main()
{
    l = read (), r = read ();
    int sum = 0;
    for (int i = 1; i <= 100; i++)
    {
        int lst = sum + 1;
        sum += (1ll << (i - 1));
        int b, e, cnt;
        if (sum >= l)
        {
            if (i & 1)
            {
                b = 2 * (sum1 + 1 + ((l > lst) ? l - lst : 0)) - 1;
                cnt = min (r, sum) - max (lst, l) + 1; cnt %= mods;
                e = b + 2 * (cnt - 1);
                ans += (b + e) % mods * cnt % mods * INV % mods;
            }
            else
            {
                b = 2 * (sum2 + 1 + ((l > lst) ? l - lst : 0));
                cnt = min (r, sum) - max (lst, l) + 1; cnt %= mods;
                e = b + 2 * (cnt - 1);
                ans += (b + e) % mods * cnt % mods * INV % mods;
            }
            ans %= mods;
        }
        if (sum >= r  || sum > 1e18) break;
        if (i & 1) sum1 += (1ll << (i - 1));
        else sum2 += (1ll << (i - 1));
    }
    printf ("%lld\n", ans);
    return 0;
}

Stas and the Queue at the Buffet

解析:

题目大意:

共有 \(n\) 个人,第 \(i\) 个人有属性值 \(a_i,b_i\),现在要给这 \(n\) 个人重排顺序,设第 \(i\) 个人站在位置 \(j\),则他的不满意度是 \(a_i \times (j-1) + b_i \times (n-j)\)

最小化所有人的不满意度之和,求这个最小值


思路:

我们变一下式子:

\[\sum_{i=1}^{n}a_i\times (i-1)+b_i\times (n-i)\\ \sum_{i=1}^{n}a_i\times i-a_i-b_i\times i\\ n\times \sum_{i=1}^n b_i+\sum_{i=1}^na_i+\sum_{i=1}^{n}(a_i-b_i)\times i\\ \]

问题变为 \(\sum_{i=1}^n(a_i-b_i)\times i\) 的最小值,我们按照 \(a_i-b_i\) 从大到小排序即可。


code:

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 10;
typedef pair <int, int> pii;
inline int read ()
{
    int x = 0, f = 1;
    char ch = getchar ();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar (); }
    while (ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar (); }
    return x * f;
}
int n;
struct node {
    int x, y, z;
    bool operator < (const node &A) const {
        return z > A.z;
    }
} a[N];
signed main()
{
    n = read ();
    for (int i = 1; i <= n; i++)
        a[i].x = read (), a[i].y = read (), a[i].z = a[i].x - a[i].y;
    sort (a + 1, a + n + 1);
    int ans = 0;
    for (int i = 1; i <= n; i++) ans += a[i].x * (i - 1) + a[i].y * (n - i);
    printf ("%lld\n", ans); 
    return 0;
}

Number of Components

解析:

题目大意:

有一条 \(n(1 \leq n \leq 10^5)\) 个节点的链,编号相邻节点有边,每个点一个权值 \(a_i(1 \leq a_i \leq n)\)\(f(l,r)\)定义为权值在\([l,r]\) 的点中的连通块数量求 \(\sum_{l=1}^{n}\sum_{r=l}^{n} f(l,r)\)


思路:

考虑套路:连通块个数=所有权值在 \([l,r]\) 内的点的个数 \(-\) 连接他们的边的个数,这个是可以分开计算的。

我们考虑每个点对答案的贡献,不难发现对于 \(l\leq a_i \and a_i \leq r\) 的所有区间这个点都贡献了一次,答案为 \(a_i\times (n-a_i+1)\) ,这部分可以线性解决。

边权同理,我们把 \(a_i\rightarrow a_{i+1}\) 的边当作是一个点,类似二维数点,考虑 \(\forall l, r|l\in[1,\min(a_i,a_{i+1})],r\in[\max(a_i,a_{i+1}), n]\)\((l,r)\) 都会对答案造成 \(-1\) 的贡献,一共贡献了 \(\min(a_i,a_{i+1})\times(n-\max(a_i,a_{i+1}+1))\) 次。

总联通块个数做差即可,时间复杂度线性。


code:

#include <bits/stdc++.h>
#define int long long
using namespace std;
typedef pair <int, int> pii;
inline int read ( )
{
    int x = 0, f = 1;
    char ch = getchar ( );
    while (ch < '0' || ch > '9') {if (ch == '-') f = - 1; ch = getchar ( );}
    while (ch >= '0' && ch <='9') {x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar ( );}
    return x * f;
}
int n, ans;
signed main()
{
    n = read (); int lst, now;
    for (int i = 1; i <= n; i++)
    {
        now = read (); 
        ans += (now * (n - now + 1));
        if (i > 1) ans -= (min (lst, now) * (n - max (lst, now) + 1));
        lst = now;
    }
    printf ("%lld\n", ans);
    return 0;
}

Sonya and Informatics

解析:

题目大意:

给一个长度为 \(n\) \((n\leq 100)\)\(0/1\) 串,进行 \(k\) \((k \leq 10^9)\) 次操作,每次操作随机选择两个位置 \(i,j\) \((1 \leq i < j \leq n)\),交换 \(i,j\) 上的数,求 \(k\) 次操作后,该 \(0/1\) 串变成非降序列的概率,答案对 \(10^9+7\) 取模。


思路:

考虑非降要求最终序列一定是前面是 0 后面是 1,假设 0 有 \(cnt\) 个,那么设 \(dp_{i,j}\) 表示交换了 \(i\) 次后前 \(cnt\) 个位置有 \(j\)\(0\),那么有转移:

\[dp_{i+1,j+1}=dp_{i+1,j+1}+dp_{i,j}\times \frac{(cnt-j)^2}{\frac{n\times (n-1)}{2}} \]

其中 \(\frac{n\times (n-1)}{2}\) 可以预处理逆元,\((cnt-j)^2\) 表示恰好选到前 \(cnt\) 个位置中的 1 的和后 \(n-cnt\) 中 0 的概率。

同时有转移:

\[dp_{i+1,j-1}=dp_{i+1,j-1}+dp_{i,j}\times \frac{j\times (n-cnt-(cnt-j))}{\frac{n\times (n-1)}{2}} \]

\(j\times (n-cnt-(cnt-j))\) 表示恰好选到前 \(cnt\) 个位置中的 0 的和后 \(n-cnt\) 中 1 的概率。

剩下的转移到 \(dp_{i+1,j}\) 即可。

我们发现 \(n\leq 100\)\(k\leq 10^9\) ,这显然可以矩快优化dp,我们设计如下矩阵:

\[A=\begin{bmatrix} P(3,0)&P(1,0)&0&0&0&\cdots &0\\ P(2,1)&P(3,1)&P(1,1)&0&0&\cdots &0\\ 0&P(2,2)&P(3,2)&P(1,2)&0&\cdots &0\\ 0&0&P(2,3)&P(3,3)&P(1,3)&\cdots &0\\ \vdots & \vdots & \vdots &\vdots&\vdots & \ddots & \vdots \\ 0&0&0&0&0&\cdots &P(3,cnt)\\ \end{bmatrix} \]

其中 \(P(i,j)\) 表示第 \(i\) 类转移,转移前的前 \(cnt\) 个中有 \(j\) 个 0,那么有:

\[\begin{bmatrix} dp_{i,0}&dp_{i,1}&dp_{i,2}&\cdots &dp_{i,cnt} \end{bmatrix} \times A = \begin{bmatrix} dp_{i+1,0}&dp_{i+1,1}&dp_{i+1,2}&\cdots &dp_{i+1,cnt} \end{bmatrix} \]

考虑设初始状态 \(dp_{0,x}=1\),其中 \(x\) 表示前 \(cnt\) 个中的 0 的数量,那么答案为:

\[\begin{bmatrix} dp_{0,0}&dp_{0,1}&dp_{0,2}&\cdots &dp_{0,cnt} \end{bmatrix} \times A^k = \begin{bmatrix} dp_{m,0}&dp_{m,1}&dp_{m,2}&\cdots &dp_{m,cnt} \end{bmatrix} \]

则答案为 \(dp_{m,cnt}\)

时间复杂度 \(\mathcal O(n^3\log k)\)


code:

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 100 + 10;
const int mods = 1e9 + 7;
typedef pair <int, int> pii;
inline int read ()
{
    int x = 0, f = 1;
    char ch = getchar ();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar (); }
    while (ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar (); }
    return x * f;
}
int n, m;
int a[N], cnt;
struct Matrix {
    int h, r;
    int m[N][N];
    void init () { for (int i = 1; i <= h; i++) m[i][i] = 1; }
}ans;
Matrix operator * (const Matrix x, const Matrix y)
{
    Matrix res;
    res.h = x.h; res.r = y.r;
    memset (res.m, 0, sizeof (res.m));
    for (int i = 1; i <= x.h; i++)
        for (int j = 1; j <= y.r; j++)
            for (int k = 1; k <= x.r; k++)
                (res.m[i][j] += ((x.m[i][k] * y.m[k][j]) % mods)) %= mods;
    return res;
}
Matrix qpow (Matrix a, int p)
{
    Matrix res;
    res.h = res.r = a.h;
    res.init ();
    while (p) {  if (p & 1) res = res * a; a = a * a; p >>= 1; }
    return res;
}
int qpow2 (int a, int p)
{
    int res = 1;
    while (p) { if (p & 1) res = (res * a) % mods; a = (a * a) % mods; p >>= 1; }
    return res;
}
signed main()
{
    n = read (), m = read ();
    for (int i = 1; i <= n; i++) a[i] = read (), cnt += !(a[i]);
    ans.h = 1, ans.r = cnt + 1;
    int cnt2 = 0;
    for (int i = 1; i <= cnt; i++) cnt2 += !(a[i]);
    ans.m[1][cnt2 + 1] = 1;
    Matrix e;
    e.h = e.r = cnt + 1;
    int inv = qpow2 (n * (n - 1) / 2, mods - 2);
    for (int i = 0; i <= cnt; i++)
    {
        int x, y, z;
        x = ((cnt - i) * (cnt - i)) % mods;
        y = (i * (n - cnt - cnt + i)) % mods;
        z = (n * (n - 1) / 2 - x - y) % mods;
        (x *= inv) %= mods; (y *= inv) %= mods; (z *= inv) %= mods;
        e.m[i + 1][i + 1] = z; e.m[i + 1][i + 2] = x; e.m[i + 1][i] = y;
    }
    Matrix q = qpow (e, m);
    ans = ans * q;
    printf ("%lld\n", ans.m[1][cnt + 1]);
    return 0;
}
posted @ 2022-08-28 10:00  TheDarkEmperor  阅读(18)  评论(0编辑  收藏  举报