【AtCoder】Dwango Programming Contest V题解

A - Thumbnail

根据题意写代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar(‘\n‘)
#define space putchar(‘ ‘)
#define MAXN 205
#define eps 1e-8
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;char c = getchar();T f = 1;
    while(c < ‘0‘ || c > ‘9‘) {
    if(c == ‘-‘) f = -1;
    c = getchar();
    }
    while(c >= ‘0‘ && c <= ‘9‘) {
    res = res * 10 + c - ‘0‘;
    c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar(‘-‘);}
    if(x >= 10) {
    out(x / 10);
    }
    putchar(‘0‘ + x % 10);
}
int N,a[MAXN],s;
void Solve() {
    read(N);
    s = 0;
    for(int i = 0 ; i < N ; ++i) {read(a[i]);s += a[i];}
    int t = 0;
    for(int i = 1 ; i < N ; ++i) {
    if(abs(a[i] * N - s) < abs(a[t] * N - s)) t = i;
    }
    out(t);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}

B - Sum AND Subarrays

把\(\frac{N(N - 1)}{2}\)个数找出来,从大到小枚举每一位,如果这一位是1的个数超过K个,就把这一位是0的数全部删除,进行下一次枚举

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar(‘\n‘)
#define space putchar(‘ ‘)
#define eps 1e-8
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;char c = getchar();T f = 1;
    while(c < ‘0‘ || c > ‘9‘) {
    if(c == ‘-‘) f = -1;
    c = getchar();
    }
    while(c >= ‘0‘ && c <= ‘9‘) {
    res = res * 10 + c - ‘0‘;
    c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar(‘-‘);}
    if(x >= 10) {
    out(x / 10);
    }
    putchar(‘0‘ + x % 10);
}
int N,K;
int64 a[1005],s[1005];
vector<int64> v,tmp;
void Solve() {
    read(N);read(K);
    for(int i = 1 ; i <= N ; ++i) {
    read(a[i]);
    s[i] = s[i - 1] + a[i];
    }
    for(int i = 1 ; i <= N ; ++i) {
    for(int j = i ; j <= N ; ++j) {
        v.pb(s[j] - s[i - 1]);
    }
    }
    int64 ans = 0;
    for(int i = 40 ; i >= 0 ; --i) {
    tmp.clear();
    for(auto t : v) {
        if(t >> i & 1) tmp.pb(t);
    }
    if(tmp.size() >= K) {
        ans |= (1LL << i);
        v.clear();v = tmp;
    }
    }
    out(ans);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}

C - k-DMC

从后往前维护一个单调队列维护C,由于我们每次遇到一个M,会把队列里所有的C都+1,那我们标记就不下放,每次新来一个C初始值设成标记的相反数即可

遇到一个D把C的坐标离D超过K的全部删除,然后队列里的总和即是这个D的贡献

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar(‘\n‘)
#define space putchar(‘ ‘)
#define eps 1e-8
#define MAXN 1000005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;char c = getchar();T f = 1;
    while(c < ‘0‘ || c > ‘9‘) {
    if(c == ‘-‘) f = -1;
    c = getchar();
    }
    while(c >= ‘0‘ && c <= ‘9‘) {
    res = res * 10 + c - ‘0‘;
    c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar(‘-‘);}
    if(x >= 10) {
    out(x / 10);
    }
    putchar(‘0‘ + x % 10);
}
char s[MAXN];
int N,Q,K;
int val[MAXN],add;
int que[MAXN],ql,qr;

void Solve() {
    read(K);
    ql = 1;qr = 0;
    add = 0;
    int64 sum = 0,ans = 0;
    for(int i = N ; i >= 1 ; --i) {
    if(s[i] == ‘C‘) {que[++qr] = i;val[i] = -add;sum += val[i];}
    else if(s[i] == ‘M‘) ++add;
    else if(s[i] == ‘D‘){
        while(ql <= qr && que[ql] - i >= K) {sum -= val[que[ql++]];}
        if(ql <= qr) {
        ans += sum + 1LL * add * (qr - ql + 1);
        }
    }
    }
    out(ans);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    read(N);
    scanf("%s",s + 1);
    read(Q);
    while(Q--) {
    Solve();
    }
}

D - Square Rotation

只想出了500算法QAQ

我们考虑每个点\((x,y)\)可以转成\((x % D,y % D)\),然后变成等价的一堆点,只不过需要隔\(D\)排开

左下角只能是\((0,0)\)到\((D - 1,D - 1)\)

考虑一个矩形边长为\(aD + b\),以左下角在\((0,0)\)为例

对于\(A_{i,j}\)表示\(x % D == i\)且\(y % D == j\)的点的个数

对于\(i,j <= b\)能被覆盖的点是\((a + 1)^2\)

对于\(i,j > b\)能被覆盖的点是\(a^2\)

其余情况都是\(a(a + 1)\)

显然考虑一下,我们的\(a\)必须是\((a + 1)^2 >= max(A_{i,j})\)

然后对于\(aD + D - 1\)一定能覆盖所有点,所以只要考虑\(b\)就好了

我们从(0,0)开始,计算最小的合法的\(b\),然后再枚举剩余的点作为左下的点,如果能从当前的\(b\)减小则减小,不行则跳出,由于\(b\)最多减小\(D\)次,复杂度是\(O(D^2)\)的

那么对于一个左下的点\(x,y\)怎么判断\(aD + b\)是否能构成一个合法的矩形呢

我们把有值的\(A_{i,j}\)跳出来,然后把\(a^2 <A_{i,j} <= a(a + 1)\)的位置在一个二维数组里加上1,把\(a(a + 1) < A_{i,j} <= (a + 1)^2\)的位置在另一个二维数组里加上1,维护成前缀和

查询的时候看看\(a^2 <A_{i,j} <= a(a + 1)\)在没在出现\(a^2\)的地方出现

和\(a(a + 1) < A_{i,j} <= (a + 1)^2\)在没在出现\(a^2\)和\(a(a + 1)\)的地方出现

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar(‘\n‘)
#define space putchar(‘ ‘)
#define eps 1e-8
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;char c = getchar();T f = 1;
    while(c < ‘0‘ || c > ‘9‘) {
    if(c == ‘-‘) f = -1;
    c = getchar();
    }
    while(c >= ‘0‘ && c <= ‘9‘) {
    res = res * 10 + c - ‘0‘;
    c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar(‘-‘);}
    if(x >= 10) {
    out(x / 10);
    }
    putchar(‘0‘ + x % 10);
}
int cnt[1005][1005],N,D,a;
int s2[1005][1005],s3[1005][1005];
int sum2(int x1,int y1,int x2,int y2) {
    if(x1 > x2 || y1 > y2) return 0;
    ++x1,++y1,++x2,++y2;
    return s2[x2][y2] - s2[x2][y1 - 1] - s2[x1 - 1][y2] + s2[x1 - 1][y1 - 1];
}
int sum3(int x1,int y1,int x2,int y2) {
    if(x1 > x2 || y1 > y2) return 0;
    ++x1,++y1,++x2,++y2;

    return s3[x2][y2] - s3[x2][y1 - 1] - s3[x1 - 1][y2] + s3[x1 - 1][y1 - 1];
}
bool check2(int x,int y,int b) {
    int d1 = sum2(max(0,b + x - D + 1),max(0,b + y - D + 1),x - 1,y - 1);
    int d2 = sum2(x + b + 1,y + b + 1,D - 1,D - 1);
    int d3 = sum2(max(0,b + x - D + 1),y + b + 1,x - 1,D - 1);
    int d4 = sum2(x + b + 1,max(0,b + y - D + 1),D - 1,y - 1);
    return !d1 && !d2 && !d3 && !d4;
}
bool check3(int x,int y,int b) {
    int d1 = sum3(x + b + 1,0,D - 1,D - 1);
    int d2 = sum3(0,y + b + 1,D - 1,D - 1);
    int d3 = sum3(max(0,b + x - D + 1),0,x - 1,D - 1);
    int d4 = sum3(0,max(0,b + y - D + 1),D - 1,y - 1);
    return !d1 && !d2 && !d3 && !d4;
}
void Solve() {
    read(N);read(D);
    int x,y;
    for(int i = 1 ; i <= N ; ++i) {
    read(x);read(y);
    cnt[x % D][y % D]++;
    }
    int t = 0;
    for(int i = 0 ; i < D ; ++i) {
    for(int j = 0 ; j < D ; ++j) {
        if(cnt[i][j]) {
        t = sqrt(cnt[i][j]);
        if(t * t < cnt[i][j]) ++t;
        a = max(t - 1,a);
        }
    }
    }
    for(int i = 0 ; i < D ; ++i) {
    for(int j = 0 ; j < D ; ++j) {
        if(cnt[i][j] > a * a && cnt[i][j] <= a * (a + 1)) s2[i + 1][j + 1]++;
        else if(cnt[i][j] > a * (a + 1)) s3[i + 1][j + 1]++;
    }
    }
    for(int i = 1 ; i <= D ; ++i) {
    for(int j = 1 ; j <= D ; ++j) {
        s2[i][j] = s2[i][j] + s2[i - 1][j] + s2[i][j - 1] - s2[i - 1][j - 1];
        s3[i][j] = s3[i][j] + s3[i - 1][j] + s3[i][j - 1] - s3[i - 1][j - 1];
    }
    }
    int b;
    for(b = 0 ; b < D ; ++b) {
    if(check2(0,0,b) && check3(0,0,b)) break;
    }
    for(int i = 0 ; i < D ; ++i) {
    for(int j = 0 ; j < D ; ++j) {
        if(!(i + j)) continue;
        while(b) {
        if(check2(i,j,b - 1) && check3(i,j,b - 1)) --b;
        else break;
        }
    }
    }
    out(a * D + b);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}

E - Cyclic GCDs

这题真的,过于神仙QAQ

思路清晰,结论显然,代码好写,完全就是虐我这种没有智商的蒟蒻的

显然我们要把点排序,这样的话我们每次建立环的时候第一次遇到的点一定是要被乘起来的

我们考虑一个\(DP[i][j]\)表示考虑了排序后的前\(i\)个点,然后建了\(j\)个环的价值(有点像第一类斯特林数啊)

然后\(b_i =DP[N][i]\)

考虑转移有\(i * DP[i][j] \rightarrow DP[i + 1][j]\)表示把第\(i + 1\)个点放到原先存在的圈中

\(a_{i + 1} * DP[i][j] \rightarrow DP[i + 1][j + 1]\)表示把第\(i + 1\)个点自成一圈

然后用一点生成函数的小知识显然可以得到

\(P_(i + 1)(x) = (a_{i + 1}x + i)P_{i}(x)\)

\(P_{0}(x) = 1\)

然后就可以得到\(P_{n}(x) = (a_{1}x + 0)(a_{2}x + 1)(a_{3}x + 2)...(a_{n}x + n - 1)\)

然后我们需要开个脑洞,再证个结论

\(c(P)\)表示多项式\(P\)每个系数的最大公约数

那么\(c(PQ) = c(P)c(Q)\)

为什么呢,可以这么想,首先\(c(P)c(Q)\)一定是\(c(PQ)\)所有系数的一个约数,我们把这些约数都除掉,现在我们要证明\(c(P) = c(Q) = 1\)的时候,满足\(c(PQ) = 1\)

如果\(P\)是\(k\)项,\(Q\)是\(m\)项

那么一定可以得到\(PQ\)的第一项是

\(r_{k}s_{m}x^{k + m}\)

然后如果\(c(PQ)\)有一个质因子是\(p\)

那么\(r_{k}\)和\(s_{m}\)中至少有一个是\(p\)的倍数

如果\(r_{k}\)是\(p\)的倍数,那么我们把\(r_{k}x^k\)从\(P\)中删去(因为我相当于用\(r_{k}x^{k}\)进行一次暴力卷积又对\(p\)取模)

\(s_{m}\)是\(p\)的倍数同理

然后就变成了\(\prod_{i = 1}^{n} gcd(a_{i},i - 1)\)

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar(‘\n‘)
#define space putchar(‘ ‘)
#define eps 1e-8
#define MAXN 100005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;char c = getchar();T f = 1;
    while(c < ‘0‘ || c > ‘9‘) {
    if(c == ‘-‘) f = -1;
    c = getchar();
    }
    while(c >= ‘0‘ && c <= ‘9‘) {
    res = res * 10 + c - ‘0‘;
    c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar(‘-‘);}
    if(x >= 10) {
    out(x / 10);
    }
    putchar(‘0‘ + x % 10);
}
const int MOD = 998244353;
int N,A[MAXN];
int inc(int a,int b) {
    return a + b >= MOD ? a + b - MOD : a + b;
}
int mul(int a,int b) {
    return 1LL * a * b % MOD;
}
int gcd(int a,int b) {
    return b == 0 ? a : gcd(b,a % b);
}
void Solve() {
    read(N);
    for(int i = 1 ; i <= N ; ++i) read(A[i]);
    sort(A + 1,A + N + 1);
    int ans = 1;
    for(int i = 1 ; i <= N ; ++i) ans = mul(ans,gcd(A[i],i - 1));
    out(ans);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}

原文地址:https://www.cnblogs.com/ivorysi/p/10027789.html

时间: 2024-07-30 14:00:03

【AtCoder】Dwango Programming Contest V题解的相关文章

Dwango Programming Contest V 翻车记

A:签到. #include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 110 char getc(){char c=getchar();while ((c<'A'||c&

[AtCoder] NIKKEI Programming Contest 2019 (暂缺F)

[AtCoder] NIKKEI Programming Contest 2019 ??本来看见这一场的排名的画风比较正常就来补一下题,但是完全没有发现后两题的AC人数远少于我补的上一份AtCoder. A - Subscribers ??首先始终 \(max = \min(A, B)\) ,\(min\) 的话如果 \(A + B \leq N\) ,那么就是 \(0\) ,否则就是 \(A + B - N\) . int n, a, b; int main() { read(n), read

Atcoder Yahoo Programming Contest 2019 简要题解

A-C 直接放代码吧. A int n,k; int main() { n=read();k=read(); puts(k<=(n+1)/2?"YES":"NO"); return 0; } B int d[N];pair<int,int>s[10]; int main() { for(int i=1,u,v;i<=3;i++){ u=read();v=read(); s[i].first=u;s[i].second=v; d[u]++;d[

AtCoder NIKKEI Programming Contest 2019 C. Different Strokes (贪心)

题目链接:https://nikkei2019-qual.contest.atcoder.jp/tasks/nikkei2019_qual_C 题意:给出 n 种食物,Takahashi 吃下获得 ai 快乐值,Aoki 吃下获得 bi 快乐值,两人轮流吃,他们的目标是最大化自己获得的快乐值减去她人获得的快乐值吗,问最后该值是多少. 题解:易知 Takahashi 要最大化答案而 Aoki 要最小化答案,考虑全部食物由 Aoki 吃下,则ans = -(b1 + b2 + .... + bn),

atcoder NIKKEI Programming Contest 2019 E - Weights on Vertices and Edges

题目链接:Weights on Vertices and Edges 题目大意:有一个\(n\)个点\(m\)条边的无向图,点有点权,边有边权,问至少删去多少条边使得对于剩下的每一条边,它所在的联通块的点权值和大于等于该边的边权 其实是蛮简单的一道题目,为什么当时就自闭了呢... 正向删边明显不靠谱,于是我们考虑反向加边,答案就是\(m-\)加入的边数 我们按照边权排序,使用并查集维护点权值和,同时记录一个\(cnt\)数组表示当前存在于该联通块内但未加入答案的边数 如果说当前联通块的点权值和大

AtCoder AISing Programming Contest 2019 Task D. Nearest Card Game

题目分析在代码注释里. int main() { #if defined LOCAL && !defined DUIPAI ifstream in("main.in"); cin.rdbuf(in.rdbuf()); // ofstream out("main.out"); // cout.rdbuf(out.rdbuf()); #endif int n, q; scan(n, q); vi a(n); scan(a); vl sum(n); sum

Dwango Programming Contest 6th C

Cookie Distribution 题意概述 : 有 \(N\) 个孩子,用 \(K\) 天给孩子们发糖果 第 \(i\) 天有 \(a_i\) 个糖果,等概率地发给这 \(n\) 个孩子(每一天每个孩子最多可以获得一个糖果),设 \(K\) 天后第 \(i\) 个孩子获得的糖果为 \(c_i\) 求 \(\prod_{i = 1}^n c_i\) 的期望乘上 \(\prod_{i = 1}^n \binom N {a_i}\) ,答案对 \(10^9 + 7\) 取模.. \(N \le

Dwango Programming Contest 6th Task C. Cookie Distribution

The answer is number of N-tuples (d[1], d[2], ..., d[N]) in all outcomes, where d[i] means on which day the i-th child get a cookie. Now consider in how many outcomes is there a particular N-tuple (d[1], d[2], ..., d[N]) as described. The answer turn

Dwango Programming Contest 6th -B

期望 按每个空隙计算 对于第$i$个空隙 对于第$j$个跨过这段的概率是$\frac{1}{i-j+1}$ 因为跨过当且仅当$[j+1,i]$之间都不先于$j$合并 求一个逆元前缀和即可 #include <bits/stdc++.h> using namespace std; const int maxn = 1e5 + 5, P = 1e9 + 7; int n; int x[maxn], inv[maxn]; int main() { ios::sync_with_stdio(false