欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Codeforces Round #519 by Botan Investments

程序员文章站 2022-05-09 17:38:28
...

Codeforces Round #519 by Botan Investments


A. Elections

#include <bits/stdc++.h>
using namespace std;
int n, mx = 0, sum = 0, x;
int main() {
    scanf("%d",&n);
    for(int i = 1; i <= n; ++i) 
        scanf("%d",&x), sum += x, mx = max(mx, x);
    int k;
    
    for(k = mx; k <= 500; ++k) {
        if(k*n > (sum<<1)) {
            printf("%d\n",k); return 0;
        }
    }
    return 0;
}

B. Lost Array

做法:枚举k判断合法性,根据前k+1个a,求出x,再进行判断即可。

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int n, cnt, b[1111];
ll a[1111], x[1111];
int ck(int k) {
    for(int i = 0; i < k; ++i) x[i] = a[i+1] - a[i];
    ll b = 0;
    for(int i = 1; i <= n; ++i) {
        b = b + x[(i-1)%k];
        if(b != a[i]) return 0;
    }
    return 1;
}
int main() {
    scanf("%d",&n);
    for(int i = 1; i <= n; ++i) scanf("%lld",&a[i]);
    for(int k = 1; k <= n; ++k) {
        if(ck(k)) b[++cnt] = k;
    }
    printf("%d\n",cnt);
    for(int i = 1; i<= cnt; ++i) printf("%d ",b[i]); puts("");
    return 0;
}

C. Smallest Word

做法:从前到和维护一个前i个字符能构成字典序最小的串,然后对于第i个串,需要考虑前i-1个字符形成的串,以及加入第i个字符后是否反转,转移即可。

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int n, ans[1111];
char str[1111];
bool operator < (const string a, const string b) {
    for(int i = 0; i < a.size(); ++i) if(a[i] != b[i]) return a[i] < b[i];
    return 1;
}
string cal(string s) {
    string t = s;
    reverse(t.begin(), t.end());
    return min(t,s);
}

int main() {
    scanf("%s", str+1); n = strlen(str+1);
    string s, t1, t2, t11, t22; s += str[1];
    for(int i = 2; i <= n; ++i) {
        t1 = t2 = s;
        t1 += str[i];
        reverse(t2.begin(), t2.end()); t2 += str[i];
        t11 = t1;   reverse(t11.begin(), t11.end());
        t22 = t2;   reverse(t22.begin(), t22.end());    
        s = min(min(t1,t2), min(t11, t22));
        if(s == t1) continue;
        else if(s == t2) ans[i-1]^=1;
        else if(s == t11) ans[i]^=1;
        else ans[i-1]^=1, ans[i]^=1;
    }
    for(int i = 1; i <= n; ++i) printf("%d ",ans[i]); puts("");
    return 0;
}

D. Mysterious Crime

做法:贪心的满足第一个串,然后根据第一个串判断所有的串最长匹配到什么位置,匹配失败后,就将这段区间的数字的答案计算完成了。然后,继续枚举下一段即可,这样已经计算的数字一定是最优的。

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int n, m, b[100007], pos[12][100007], p[12], a[12][100007];
bool ck() {
    if(b[a[1][p[1]]]) return 0;
    if(p[1] > n) return 0;
    for(int i = 2; i <= m; ++i) {
        if(p[i] > n || a[i][p[i]] != a[i-1][p[i-1]] || b[a[i][p[i]]]) return 0;
    }
    return 1;
}
void cal(int x) {
    int ans = 0;
    for(int i = 1; i <= m; ++i) p[i] = pos[i][x];
    while(ck()) {
        for(int i = 1; i <= m; ++i) ++p[i];
        ++ans;
    }
    for(int j = pos[1][x], t = ans; t ; ++j, --t) b[a[1][j]] = t;
    return;
}
int main() {
    scanf("%d%d",&n,&m);
    for(int i = 1; i <= m; ++i)
        for(int j= 1; j <= n; ++j) {
            scanf("%d",&a[i][j]);
            pos[i][a[i][j]] = j;
        }

    for(int i = 1; i <= n; ++i) if(!b[a[1][i]]) {
        cal(a[1][i]);
    }
    ll ans = 0;
    for(int j = 1;j <= n; ++j) ans += 1LL*b[j];
    printf("%lld\n",ans);
    return 0;
}
/*
4 2
1 2 4 3
4 3 1 2
*/

E. Train Hard, Win Easy

做法:求\[\sum _{i=1}^n \sum_{j=1,j != i,can[i][j] = 0} ^n min(a[i].x+a[j].y, a[i].y+a[j].x)\]
首先 i,j 之间不能计算的答案可以从最终的答案中减去,那么考虑如何优化掉第二维;min提醒我们可以讨论。当\(a[i].x + a[j].y <= a[i].y + a[j].x\)\(a[i].x - a[i].y <= a[j].x - a[j].y\)时最小值是\(a[i].x + a[j].y\)
排序之后分别考虑贡献即可;另一种情况,同理。可以通过预处理解决。

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i = (a); i <= (b); ++i)
#define per(i,a,b) for(int i = (a); i >= (b); --i)
typedef long long ll;
using namespace std;
int n, m, x, y;
struct node{
    ll x, y; int id;
    bool operator < (const node &a) const { return x - y < a.x - a.y; }
}a[300007];
ll ans[300007], sx[300007], sy[300007];
int main() {
    scanf("%d%d",&n,&m);
    rep(i,1,n) scanf("%lld%lld", &a[i].x, &a[i].y), a[i].id = i;
    rep(i,1,m) {
        scanf("%d%d", &x, &y);
        ans[x] -= min(a[x].x+a[y].y, a[x].y+a[y].x);
        ans[y] -= min(a[x].x+a[y].y, a[x].y+a[y].x);
    } sort(a+1, a+1+n);
    per(i,n,1) sy[i] = sy[i+1] + a[i].y; rep(i,1,n) sx[i] = sx[i-1] + a[i].x;
    for(int num, i = 1; i <= n; ++i) {
        num = lower_bound(a+1,a+1+n,a[i])-a-1;
        ans[a[i].id] += a[i].x*(n - num - 1LL) + sy[num+1] - a[i].y + a[i].y*num + sx[num];
    }
    for(int i = 1; i<= n; ++i) printf("%lld ", ans[i]); puts("");
}

F. Make It One

做法:求至少挑多少个数可以使得他们的gcd为1。首先,可以证明最多挑7个数,因为这些数两两之间至少有一个不重复的公共素数。\(dp[i][j]\) 表示选 i 个数gcd为 j 的方案数,那么通过容斥转移就是
\[dp[i][j] = C_{num_j}^i - \sum_{k=2}^\infty dp[i][j*k] \]
\[num_j = \sum_{i=1}^n [a[i] ~mod ~j = 0]\]
即从包含j的数里挑i个的方案数,去掉包含\(j\)的倍数的方案数,这个值可能很大运算过程中取模即可。答案就是找到最小的\(i\)使得\(dp[i][1]>0\)

#include <bits/stdc++.h>
typedef long long ll;
const int N = 3e5 + 7;
const int mod = 1e9 + 7;
using namespace std;
int num[N], a[N], n, MX;
ll dp[11][N], f[N], inv[N];
ll q_pow(ll a, ll b) {
    ll ans = 1;
    while(b) {
        if(b&1) ans = (ans*a) % mod;
        a = (a*a) % mod;
        b >>= 1LL;
    }
    return ans;
}
void init() {
    f[0] = 1;
    for(int i = 1; i <= 3e5; ++i) f[i] = (f[i-1]*i) % mod;
    inv[300000] = q_pow(f[300000], mod-2);
    for(int i = 300000-1; i >= 0; --i) inv[i] = (inv[i+1]*(i+1LL)) % mod;
}
ll C(int n, int m) {
    if(m > n) return 0;
    if(m == n || !m ) return 1;
    return (f[n]*inv[m])%mod*inv[n-m]%mod;
}
void solve(int x) {
    for(int i = 1; i*i <= x; ++i) if(x % i == 0) {
        ++num[i];
        if(i*i == x) continue;
        ++num[x/i];
    }
}
int main() {
    init();
    scanf("%d",&n);
    for(int i = 1; i <= n; ++i) 
        scanf("%d", &a[i]), solve(a[i]), MX = max(MX,a[i]);
    for(int i = 1; i <= 7; ++i) {
        for(int j = MX; j >= 1; --j) {
            dp[i][j] = C(num[j],i);
            for(int k = j+j; k <= MX; k += j) {
                dp[i][j] -= dp[i][k];
                if(dp[i][j] < 0) dp[i][j]+=mod;
                dp[i][j] %= mod;
            }
        }
        if(dp[i][1] > 0) {
            printf("%d\n",i); return 0;
        }
    }
    puts("-1");
    return 0;
}

G. Speckled Band

做法:略猛,有缘再写了。。。