【AtCoder】Tenka1 Programmer Contest 2019

Tenka1 Programmer Contest 2019

C - Stones

题面大意:有一个01序列,改变一个位置上的值花费1,问变成没有0在1右边的序列花费最少多少

直接枚举前i个都变成0即可

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define space putchar(' ')
#define enter putchar('\n')
#define eps 1e-10
#define MAXN 200005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef unsigned int u32;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;T f = 1;char c = getchar();
    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;
char s[MAXN];
int sum[MAXN];
void Solve() {
    read(N);
    scanf("%s",s + 1);
    for(int i = 1 ; i <= N ; ++i) {
    sum[i] = sum[i - 1];
    if(s[i] == '#') sum[i]++;
    }
    int ans = N;
    for(int i = 0 ; i <= N ; ++i) {
    ans = min(ans,sum[i] + N - i - (sum[N] - sum[i]));
    }
    out(ans);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}

D - Three Colors

大意:将数分到三个标号为123的集合,要求三个集合能构成三角形

题解:也就是\(R + B + G = S\)满足\(G,R,B < \frac{S}{2}\)

不合法的情况就是有一个集合大于等于\(\frac{S}{2}\)的方案,对于等于\(\frac{S}{2}\)再用一个dp去重即可

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define space putchar(' ')
#define enter putchar('\n')
#define eps 1e-10
#define MAXN 200005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef unsigned int u32;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;T f = 1;char c = getchar();
    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;
int a[305],S;
int dp[305][90005],f[90005];
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;
}
void update(int &x,int y) {
    x = inc(x,y);
}
int fpow(int x,int c) {
    int res = 1,t = x;
    while(c) {
    if(c & 1) res = mul(res,t);
    t = mul(t,t);
    c >>= 1;
    }
    return res;
}
void Solve() {
    read(N);
    for(int i = 1 ; i <= N ; ++i) {
    read(a[i]);
    S += a[i];
    }
    dp[0][0] = 1;
    f[0] = 1;
    for(int i = 1 ; i <= N ; ++i) {
    for(int j = S ; j >= 0 ; --j) {
        update(dp[i][j],mul(2,dp[i - 1][j]));
        if(j >= a[i]) {
        update(dp[i][j],dp[i - 1][j - a[i]]);
        update(f[j],f[j - a[i]]);
        }
    }
    }
    int ans = fpow(3,N);
    for(int j = 0 ; j <= S ; ++j) {
    if(j * 2 >= S) {
        update(ans,MOD - mul(3,dp[N][j]));
    }
    }
    if(S % 2 == 0) {
    update(ans,mul(f[S / 2],3));
    }
    out(ans);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}

E - Polynomial Divisors

大意:给定多项式求多项式取所有整数值时都能被整除的质数

盲猜肯定要么是所有系数的gcd的质因数要么就小于最高次项,然后判解不会就直接暴力,以为数据造不满然后被卡死了,atc的数据还是强

事实上判解的话只要判这个多项式在modp意义下是否是多项式\(x^{p} - x\)的倍数即可

充分性显然(费马小定理)

必要性合法的式子会含有\(x(x - 1)(x - 2)..(x - (p - 1))\),然后这个东西在modp意义下是\(x^{p} - x\)相等,如果不是全等的话,必然有一个小于等于p - 1的多项式是有p个根,这不存在

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define space putchar(' ')
#define enter putchar('\n')
#define eps 1e-10
#define MAXN 10005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef unsigned int u32;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;T f = 1;char c = getchar();
    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);
}
set<int> S;
int g;
int N,a[MAXN],b[MAXN],c[MAXN];
int prime[MAXN],tot;
bool nonprime[MAXN];
int gcd(int a,int b) {
    return  b == 0 ? a : gcd(b,a % b);
}
void Solve() {
    read(N);
    for(int i = N ; i >= 0 ; --i) {
    read(a[i]);
    g = gcd(g,abs(a[i]));
    }
    for(int i = 2 ; i <= g / i ; ++i) {
    if(g % i == 0) {
        S.insert(i);
        while(g % i == 0) g /= i;
    }
    }
    if(g > 1) S.insert(g);
    for(int i = 2 ; i <= 10000 ; ++i) {
    if(!nonprime[i]) {
        prime[++tot] = i;
    }
    for(int j = 1 ; j <= tot ; ++j) {
        if(1LL * i * prime[j] > 10000) break;
        nonprime[i * prime[j]] = 1;
        if(i % prime[j] == 0) break;
    }
    }
    for(int i = 1 ; i <= tot ; ++i) {
    if(prime[i] > N) break;
    int p = prime[i];
    if(S.find(p) != S.end()) continue;
    memset(b,0,sizeof(b));
    memset(c,0,sizeof(c));
    bool flag = 1;
    for(int i = N ; i >= 0 ; --i) {
        b[i] = (a[i] + c[i]) % p;
        if(i >= p) {
        c[1 + i - p] += b[i];
        c[1 + i - p] %= p;
        }
        else if(b[i]){
        flag = 0;break;
        }
    }
    if(flag) S.insert(p);
    }
    for(auto t : S) {
    out(t);enter;
    }
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}

F - Banned X

大意:找到一个长度为N序列只含0,1,2,求其中任意一段连续的和不为x的答案

首先统计所有和小于x的答案

然后就是如果x为奇数,我只选2且序列总和大于x的答案

然后就是,因为我每一段的和都不是x,每次增加是1或2,那么肯定存在一个和是\(X - 1\)的前缀和

此时我只能选2,如果序列开头第一个不为0的数是2,那么我可以删掉这个2,往后继续加一个2,直到我删掉时遇到了一个1

所以我们枚举i个2+1个1的序列,枚举构成X - 1所用的序列长度,之后只能往后加不超过i个2即可

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define space putchar(' ')
#define enter putchar('\n')
#define eps 1e-10
#define MAXN 10005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef unsigned int u32;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;T f = 1;char c = getchar();
    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,X;
int dp[3005][6005],fac[6005],invfac[6005];
int f[3005];
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;
}
void update(int &x,int y) {
    x = inc(x,y);
}
int fpow(int x,int c) {
    int res = 1,t = x;
    while(c) {
    if(c & 1) res = mul(res,t);
    t = mul(t,t);
    c >>= 1;
    }
    return res;
}
int C(int n,int m) {
    if(n < m) return 0;
    return mul(fac[n],mul(invfac[m],invfac[n - m]));
}
void Solve() {
    read(N);read(X);
    dp[0][0] = 1;
    fac[0] = 1;
    for(int i = 1 ; i <= 2 * N ; ++i) fac[i] = mul(fac[i - 1],i);
    invfac[2 * N] = fpow(fac[2 * N],MOD - 2);
    for(int i = 2 * N - 1 ; i >= 0 ; --i) {
    invfac[i] = mul(invfac[i + 1],i + 1);
    }
    int ans = 0;
    for(int i = 1 ; i <= N ; ++i) {
    for(int j = 2 * i ; j >= 1 ; --j) {
        if(j >= 2) update(dp[i][j],dp[i - 1][j - 2]);
        if(j >= 1) update(dp[i][j],dp[i - 1][j - 1]);
    }
    }
    for(int i = 0 ; i <= N ; ++i) {
    for(int j = 0 ; j <= 2 * i ; ++j) {
        if(j < X) update(ans,mul(dp[i][j],C(N,i)));
    }
    }
    for(int i = 1 ; i < N ; ++i) {
    int t = i * 2 + 1;
    if(t >= X) break;
    for(int j = 0 ; j <= N ; ++j) {
        if(i + j + 2 <= N) {
        update(f[i + j + 2],dp[j][X - 1 - t]);
        if(i + j + i + 2 <= N) update(f[i + j + i + 2],MOD - dp[j][X - 1 - t]);
        }
    }
    }
    for(int i = 1 ; i <= N ; ++i) f[i] = inc(f[i],f[i - 1]);
    for(int i = 1 ; i <= N ; ++i) {
    update(ans,mul(f[i],C(N,i)));
    }
    if(X & 1) {
    for(int i = 1 ; i <= N ; ++i) {
        if(i * 2 > X) update(ans,C(N,i));
    }
    }
    out(ans);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}

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

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

【AtCoder】Tenka1 Programmer Contest 2019的相关文章

【AtCoder】AISing Programming Contest 2019

本来以为是1199rated的..仔细一看发现是1999,所以就做了一下 这场涨分很轻松啊...为啥又没打 等pkuwc考完我一定打一场atcoder(咕咕咕,咕咕咕,咕咕咕咕咕咕咕~) 但是其实我思维速度上真的有点不行... A - Bulletin Board 输出\((N - W + 1)(N - H + 1)\) #include <bits/stdc++.h> #define fi first #define se second #define pii pair<int,int

Atcoder Tenka1 Programmer Contest 2019

C 签到题,f[i][0/1]表示以i结尾最后一个为白/黑的最小值,转移显然. #include<bits/stdc++.h> using namespace std; const int N=2e5+7; int n,f[N][2]; char s[N]; int main() { scanf("%d",&n); scanf("%s",s+1); for(int i=1;i<=n;i++) if(s[i]=='.') { f[i][0]=

【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

Tenka1 Programmer Contest 2019 D - Three Colors

Three Colors 思路:dp 设sum为所有边的总和 不能组成三角形的情况:某条边长度>=ceil(sum/2),可以用dp求出这种情况的方案数,然后用总方案数减去就可以求出答案. 注意当某两条边都为sum/2的时候,dp会多算一次,要减去多算的方案数,多算的方案数也可以用dp求 代码: #pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize(4) #include<bits/stdc++.h> u

Tenka1 Programmer Contest C - Align

链接 Tenka1 Programmer Contest C - Align 给定一个序列,要求重新排列最大化\(\sum_{i=2}^{i=n} |a_i-a_{i-1}|\),\(n\leq 10^5\) 小清新贪心,首先把最大的先放好,然后依次考虑下面四种决策: 左边放最小,右边放最小,左边放最大,右边放最大. 每次取\(max\)并更新左右端点,这样一定能取到最大最小的波浪形态,最大值旁边放两个最小不会更差. #include<bits/stdc++.h> #define R regi

【Atcoder】ARC 080 E - Young Maids

[算法]数学+堆 [题意]给定n个数的排列,每次操作可以取两个数按序排在新序列的头部,求最小字典序. [题解] 转化为每次找字典序最小的两个数按序排在尾部,则p1和p2的每次选择都必须满足:p1在当前序列的奇数位置,p2在当前序列的偶数位置且位于p1之后.满足条件的情况下每次找最小. 每次找到p1和p2都把序列划分为3部分,递归进行,初步想到使用归并. 进一步考虑性质,每对数字要出现必须它的上属序列的p1和p2必须出现,此外没有其他要求. 所以用优先队列维护每个序列,序列的优先级为p1,每次处理

【Atcoder】ARC083 D - Restoring Road Network

[算法]图论,最短路? [题意]原图为无向连通图,现给定原图的最短路矩阵,求原图最小边权和,n<=300. [题解]要求最小边权和下,原图的所有边一定是所连两端点的最短路. 那么现在将所有最短路作为边加入原图,考虑删边. 对于(u,v),若存在点w使得(u,v)=(u,w)+(w,v),则(u,v)可以删去.(btw,若是>则无解) 复杂度O(n^3). #include<cstdio> #include<cstring> #include<cctype>

【AtCoder】ARC082 F - Sandglass

[链接]F - Sandglass [题意]给定沙漏A和B,分别装着a和X-a的沙子,开始时A在上B在下,每秒漏1,漏完不再漏.给定n,有n个时刻ai沙漏倒转.给定m个询问,每次询问给定初值a和时刻t,求A中沙子量. [算法]数学(函数) [题解] 先不考虑时刻,令ft(a)表示沙子初值a时,当前A中的沙子数.(x轴是初值a,y轴是沙子数num) 时刻为0时,显然是一条从0出发斜率为1的直线. 若A在上,则每过1s,整段函数都下移一个单位,碰到y=0则变成平的. 若A在下,则每过1s,整段函数都

【Atcoder】CODE FESTIVAL 2017 qual C D - Yet Another Palindrome Partitioning

[题意] 给定只含小写字母的字符串,要求分割成若干段使段内字母重组顺序后能得到回文串,求最少分割段数.n<=2*10^5 [题解] 关键在于快速判断一个字符子串是否合法,容易发现合法仅当不存在或只存在一个奇数字符,其余字符均为偶数. 当涉及到奇偶性(%2)时,很自然能想到异或. 将小写字母a~z转化2^0~2^25,那么一个字符子串合法当且仅当其连续异或值是0或2^i(0<=i<=25). 令f[i]表示前i个合法的最少段数,sum[i]表示异或前缀和,则有: f[i]=min(f[j]