1. 程式人生 > >【AtCoder】AGC021

【AtCoder】AGC021

sin 顏色 pair 高位到低位 優化 urn set 附加 fab

A - Digit Sum 2

從高位到低位數的第i位以前前綴都相同,第i位比當前位上的數小1的情況下,後面都填9
枚舉一下然後計算最大的就好

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define enter putchar(‘\n‘)
#define space putchar(‘ ‘)
#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);
}
int64 N;
int x[25],tot;
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    read(N);
    while(N) {
    x[++tot] = N % 10;
    N /= 10;
    }
    int ans = 0,sum = 0;
    for(int i = tot ; i >= 1 ; --i) {
    ans = max(ans,sum + x[i] - 1 + (i - 1) * 9);
    sum += x[i];
    }
    ans = max(ans,sum);
    out(ans);enter;
    return 0;
}

B - Holes

如果兩個點的話或者所有點共線的話兩個端點各是0.5
我們給這些點求一個凸包,由於半徑是無窮大,我們只關心凸包上的點相鄰兩邊做垂直平分線交出來的角除以2PI的值
這個值可以用PI減去凸包上的頂角求出來

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define enter putchar(‘\n‘)
#define space putchar(‘ ‘)
#define MAXN 100005
#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);
}
const db PI = acos(-1.0);
int N,top;
db ans[105];
bool dcmp(db a,db b) {
    return fabs(b - a) <= eps;
}
struct Point {
    db x,y;int id;
    Point(db _x = 0.0,db _y = 0.0) {
    x = _x;y = _y;
    }
    friend Point operator + (const Point &a,const Point &b) {
    return Point(a.x + b.x,a.y + b.y);
    }
    friend Point operator - (const Point &a,const Point &b) {
    return Point(a.x - b.x,a.y - b.y);
    }
    friend Point operator * (const Point &a,const db &d) {
    return Point(a.x * d,a.y * d);
    }
    friend db operator * (const Point &a,const Point &b) {
    return a.x * b.y - a.y * b.x;
    }
    friend db dot(const Point &a,const Point &b) {
    return a.x * b.x + a.y * b.y;
    }
    db norm() {
    return sqrt(x * x + y * y);
    }
}P[105],sta[105];

bool cmp(Point a,Point b) {
    db d = (a - P[1]) * (b - P[1]);
    if(dcmp(d,0.0)) {return (a - P[1]).norm() < (b - P[1]).norm();}
    else return d > 0;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    int x,y;
    read(N);
    if(N == 1) {puts("1.0");return 0;}
    for(int i = 1 ; i <= N ; ++i) {read(x);read(y);P[i] = Point(x,y);P[i].id = i;}
    for(int i = 2 ; i <= N ; ++i) {
    if(P[i].x < P[1].x || (P[i].x == P[1].x && P[i].y < P[1].y)) swap(P[1],P[i]);
    }
    sort(P + 2,P + N + 1,cmp);
    sta[++top] = P[1];
    for(int i = 2 ; i <= N ; ++i) {
    while(top >= 2 && (P[i] - sta[top - 1]) * (sta[top] - sta[top - 1]) >= 0.0) --top;
    sta[++top] = P[i];
    }
    if(top == 2) {
    ans[sta[1].id] = 0.5;
    ans[sta[2].id] = 0.5;
    }
    else {
    Point a,b;
    sta[0] = sta[top];sta[top + 1] = sta[1];
    for(int i = 1 ; i <= top ; ++i) {
        a = sta[i + 1] - sta[i];
        b = sta[i - 1] - sta[i];
        ans[sta[i].id] = (PI - acos( dot(a,b) / (a.norm() * b.norm()) ) ) / (2 * PI); 
    }
    }
    for(int i = 1 ; i <= N ; ++i) {
    printf("%.10lf\n",ans[i]);
    }
    return 0;
}

C - Tiling

按理來說是可以四個四個小塊一劃,如果多出來一行或者一列或者都多,就先貪心用<>填滿多的一個橫行,貪心用^v填滿多余的一個縱行
但是有一個邊界情況,就是橫行縱行都剩一個,並且填滿了,這個時候剩下了5個格子,有一個<>和一個^v沒填
用3*3舉個例子
<>^
^*v
v<>
可以這麽填
也就是我們必須填多余格子的時候盡量靠右下填四個小塊的時候盡量靠右上,剩出一個
**
**
*

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define enter putchar(‘\n‘)
#define space putchar(‘ ‘)
#define MAXN 100005
#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,M,A,B,S,T;
char ans[1005][1005];
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    read(N);read(M);read(A);read(B);
    S = N;T = M;
    if(N * M < (A + B) * 2) {
    puts("NO");
    return 0;
    }
    for(int i = 1 ; i <= N ; ++i) {
    for(int j = 1 ; j <= M ; ++j) {
        ans[i][j] = ‘.‘;
    }
    }
    if(M & 1) {
    int t = 1;
    while(B) {
        if(t + 1 > N) break;
        ans[t][M] = ‘^‘;
        ans[t + 1][M] = ‘v‘;
        t += 2;
        --B;
    }
    --M;    
    }
    if(N & 1) {
    int t = T;
    while(A) {
        if(t - 1 < 1) break;
        ans[N][t] = ‘>‘;
        ans[N][t - 1] = ‘<‘;
        t -= 2;
        --A;
    }
    --N;
    }
    int rem = N * M;
    for(int i = 1 ; i <= N ; i += 2) {
    for(int j = M - 1 ; j >= 1 ; j -= 2) {
        if(A >= 2) {
        A -= 2;
        rem -= 4;
        ans[i][j] = ‘<‘;
        ans[i][j + 1] = ‘>‘;
        ans[i + 1][j] = ‘<‘;
        ans[i + 1][j + 1] = ‘>‘;
        }
        else if(B >= 2) {
        B -= 2;
        rem -= 4;
        ans[i][j] = ‘^‘;
        ans[i + 1][j] = ‘v‘;
        ans[i][j + 1] = ‘^‘;
        ans[i + 1][j + 1] = ‘v‘;
        }
    }
    }
    if(!A || !B || rem >= 8) {
    for(int i = 1 ; i <= N ; i += 2) {
        for(int j = M - 1 ; j >= 1 ; j -= 2) {
        if(ans[i][j] != ‘.‘) continue;
        if(A) {
            --A;
            ans[i][j] = ‘<‘;
            ans[i][j + 1] = ‘>‘;
        }
        else if(B) {
            --B;
            ans[i][j] = ‘^‘;
            ans[i + 1][j] = ‘v‘;
        }
        }
    }
    }
    else if(rem >= 4){
    if(A == 1 && B == 1 && (S & 1) && (T & 1)) {
        --A;--B;
        ans[N - 1][1] = ‘<‘;ans[N - 1][2] = ‘>‘;
        ans[N][1] = ‘^‘;ans[N + 1][1] = ‘v‘;
    } 
    }
    if(A || B) {puts("NO");return 0;}
    puts("YES");
    for(int i = 1 ; i <= S ; ++i) {
    for(int j = 1 ; j <= T ; ++j) {
        putchar(ans[i][j]);
    }
    enter;
    }
    return 0;
}

D - Reversed LCS

這怎麽一道普及組題。。。
\(dp[i][j][k]\)表示區間\([i,j]\)改了\(k\)個字符
\(dp[i + 1][j][k] -> dp[i][j][k]\)
\(dp[i][j - 1][k] -> dp[i][j][k]\)
如果\(s[i] == s[j]\)
\(dp[i - 1][j + 1][k] + 2 -> dp[i][j][k]\)
如果\(s[i] != s[j]\)
\(dp[i - 1][j + 1][k] + 2 -> dp[i][j][k + 1]\)
初始化\(dp[i][i][0] = 1\)

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define enter putchar(‘\n‘)
#define space putchar(‘ ‘)
#define MAXN 100005
#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);
}
char s[305];
int K,dp[305][305][305],N;
void update(int &x,int y) {
    x = max(x,y);
}
void Solve() {
    scanf("%s",s + 1);
    read(K);
    N = strlen(s + 1);
    for(int i = 1 ; i <= N ; ++i) 
    for(int j = 0 ; j <= K ; ++j)
        dp[i][i][j] = 1;
    for(int d = 2 ; d <= N ; ++d) {
    for(int i = 1 ; i <= N ; ++i) {
        int j = i + d - 1;
        if(j > N) break;
        for(int k = 0 ; k <= K ; ++k) {
        if(k) update(dp[i][j][k],dp[i][j][k - 1]);
        update(dp[i][j][k],dp[i + 1][j][k]);
        update(dp[i][j][k],dp[i][j - 1][k]);
        if(s[i] == s[j]) update(dp[i][j][k],dp[i + 1][j - 1][k] + 2);
        else if(k) update(dp[i][j][k],dp[i + 1][j - 1][k - 1] + 2);
        }
    }
    }
    out(dp[1][N][K]);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
    return 0;
}

E - Ball Eat Chameleons

這道題的題意應該是這個序列建立出來吃的方式可以自己定的

我們分析一下,顯然紅球數必須不少於藍球數
設紅球數為\(r\),藍球數為\(b\)
我們每個寵物都要分配至少一個紅球,然後我們給\(N - 1\)個寵物都分配紅球後,剩余的都給第一個,給了\(r - (N - 1)\)
如果\(r - (N - 1) > b\),那麽無論怎樣紅藍的先後順序,我都可以讓所有寵物變紅,那麽方案數就是\(\binom{K}{r}\)

\(r != b\)
\(t = r - (N - 1)\)
設紅球為1,藍球為-1,那麽前綴和必須大於\(-t\)
可以這麽考慮,在\(N - 1\)只寵物沒有分配紅球時,來一個紅球就給他們吃一個,之後如果來了一個藍球,如果吃了紅球的寵物沒有吃過藍球,讓它們消耗一個藍球
假如不存在這樣的情況,我們就把藍球都餵給第一個,如果餵到了t個藍球,那麽我無法使第一只變紅了,我餵給別人的話,別人也沒法變紅了,所以就轉化成了這個問題
方案數類似卡特蘭數的證明
\(\binom{K}{r} - \binom{K}{r + t}\)

\(r == b\)
還是類似上述情況,我還是選擇給剩下的\(N - 1\)只各餵一個紅球,一個藍球,給第一只餵\(t\)個紅球和藍球
那麽我在給第一只餵滿\(t\)個藍球之前,我必須把第一只的\(t\)個紅球餵滿了,這就要求了這個顏色的序列的最後一個值必須是-1
我們再考慮前\(K - 1\)個位置,我必須滿足前綴和大於\(-t\),那麽答案就是\(\binom{K - 1}{r} - \binom{K - 1}{r + t}\)

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define enter putchar(‘\n‘)
#define space putchar(‘ ‘)
#define MAXN 500005
#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);
}
const int MOD = 998244353;
int N,K,fac[MAXN * 2],invfac[MAXN * 2],inv[MAXN * 2];
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 C(int n,int m) {
    if(n < m) return 0;
    return mul(fac[n],mul(invfac[m],invfac[n - m]));
}
void update(int &x,int y) {
    x = inc(x,y);
}
void Solve() {
    read(N);read(K);
    inv[1] = 1;
    for(int i = 2 ; i <= 1000000 ; ++i) inv[i] = mul(inv[MOD % i],MOD - MOD / i);
    invfac[0] = fac[0] = 1;
    for(int i = 1 ; i <= 1000000 ; ++i) {
    fac[i] = mul(fac[i - 1],i);
    invfac[i] = mul(invfac[i - 1],inv[i]);
    }
    int ans = 0;
    for(int i = 0 ; i <= K ; ++i) {
    int r = i,b = K - i;
    if(r < b || r < N) continue;
    if(r - (N - 1) > b) {
        update(ans,C(K,r));
    }
    else if(r == b) {
        int t = r - (N - 1);
        update(ans,inc(C(K - 1,r),MOD - C(K - 1,r + t)));
    }
    else {
        int t = r - (N - 1);
        update(ans,inc(C(K,r),MOD - C(K,r + t)));
    }
    }
    out(ans);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
    return 0;
}

F - Trinity

考慮\(dp[i][j]\)表示\(i\)\(j\)列方格填的方案數,多了一個限制是每行必須填一個數,所以我們枚舉\(i\),累加進答案\(\binom{n}{i} dp[i][M]\)即可

我們每次考慮增加一列的方案數
\(dp[p][j]\)轉移到\(dp[p + q][j + 1]\)的方案
如果\(q\)\(0\)的話,那麽我這一列就剩\(B\)\(C\)填的方式,有\(\binom{p + 1}{2} + 1\)多出來的1個是什麽也不選,我們相當於加了一行,然後在\(p + 1\)中選兩個,然後刪掉加的一行,這樣就包含進了這一列選了一個點的情況了

如果\(q\)不為0
我們考慮\(B,C\)可能不是我們新加進去的,而是原來\(p\)行中的,我們給\(p + q\)行首尾再加上附加的兩行,然後選擇\(q + 2\)個染黑,作為新加入的行,方案數是\(\binom{p + q + 2}{q + 2}\)
然後把多出來的兩行刪掉即可,如果刪掉的首尾兩行都沒染黑,那麽這個染黑的序列,首尾兩個黑格子都是原來\(p\)行中的,如果首和尾都染黑了,那麽這個\(p + q\)的序列,最上和最下兩個黑格子都是新加入的\(q\)行中的,如果首行黑了尾行沒黑,那麽\(p + q\)的序列,最上的格子是\(q\)行中的,最下的格子是\(p\)行中的,另一種情況同理

可以卷積優化,所以就變成\(O(nm \log n)\)的了

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define enter putchar(‘\n‘)
#define space putchar(‘ ‘)
#define MAXN 8005
#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);
}
const int MOD = 998244353,MAXL = 1 << 14;
int N,M,fac[MAXN * 2],invfac[MAXN * 2],inv[MAXN * 2];
int f[MAXL + 5],g[MAXL + 5],dp[2][MAXN],W[MAXL + 5];
int mul(int a,int b) {
    return 1LL * a * b % MOD;
}
int inc(int a,int b) {
    return a + b >= MOD ? a + b - MOD : a + b;
}
int C(int n,int m) {
    if(n < m) return 0;
    return mul(fac[n],mul(invfac[m],invfac[n - m]));
}
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 update(int &x,int y) {
    x = inc(x,y);
}
void FFT(int *p,int L,int on) {
    for(int i = 1 , j = L >> 1 ; i < L - 1 ; ++i) {
    if(i < j) swap(p[i],p[j]);
    int k = L >> 1;
    while(j >= k) {
        j -= k;
        k >>= 1;
    }
    j += k;
    }
    for(int h = 2 ; h <= L ; h <<= 1) {
    int wn = W[(MAXL + on * (MAXL / h)) % MAXL];
    for(int k = 0 ; k < L ; k += h) {
        int w = 1;
        for(int j = k ; j < k + h / 2 ; ++j) {
        int u = p[j],t = mul(w,p[j + h / 2]);
        p[j] = inc(u,t);
        p[j + h / 2] = inc(u,MOD - t);
        w = mul(w,wn);
        }
    }
    }
    if(on == -1) {
    int InvL = fpow(L,MOD - 2);
    for(int i = 0 ; i < L ; ++i) p[i] = mul(p[i],InvL);
    }
}
void Solve() {
    read(N);read(M);
    fac[0] = 1;
    for(int i = 1 ; i <= N + 10 ; ++i) fac[i] = mul(fac[i - 1],i);
    invfac[N + 10] = fpow(fac[N + 10],MOD - 2);
    for(int i = N + 9 ; i >= 0 ; --i) invfac[i] = mul(invfac[i + 1],i + 1);
    W[0] = 1;W[1] = fpow(3,(MOD - 1) / MAXL);
    for(int i = 2 ; i < MAXL ; ++i) W[i] = mul(W[i - 1],W[1]);
    int cur = 0;
    for(int i = 0 ; i <= N ; ++i) dp[cur][i] = 1;
    for(int i = 1 ; i <= N ; ++i) g[i] = invfac[i + 2];
    int L = 1;
    while(L <= 2 * N) L <<= 1;
    FFT(g,L,1);
    for(int i = 2 ; i <= M ; ++i) {
    memset(dp[cur ^ 1],0,sizeof(dp[cur ^ 1]));
    for(int j = 0 ; j <= N ; ++j) {
        update(dp[cur ^ 1][j],mul(dp[cur][j],inc(C(j + 1,2),1)));
    }
    memset(f,0,sizeof(f));
    for(int j = 0 ; j <= N ; ++j) f[j] = mul(dp[cur][j],invfac[j]);
    FFT(f,L,1);
    for(int j = 0 ; j < L ; ++j) f[j] = mul(f[j],g[j]);
    FFT(f,L,-1);
    for(int j = 0 ; j <= N ; ++j) {
        update(dp[cur ^ 1][j],mul(f[j],fac[j + 2]));
    }
    cur ^= 1;
    }
    int ans = 0;
    for(int i = 0 ; i <= N ; ++i) {
    update(ans,mul(C(N,i),dp[cur][i]));
    }
    out(ans);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
    return 0;
}

【AtCoder】AGC021