July Challenge 2018 : Picking Fruit for Chefs

传送门

好久没写题解了,就过来水两篇。

对于每一个人,考虑一个序列$A$,$A_I$表示当k取值为 i 时的答案。

如果说有两个人,我们可以把$(A+B)^k$二项式展开,这样就发现把两个人合并起来的操作就是一次卷积,直接NTT就可以了。

同类人有多个,直接暴力肯定是不行的。快速幂的话不知道会不会T,我是用了多项式取ln和exp(拉板子)。

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MN 400002
using namespace std;
int read_p,read_ca;
inline int read(){
    read_p=0;read_ca=getchar();
    while(read_ca<‘0‘||read_ca>‘9‘) read_ca=getchar();
    while(read_ca>=‘0‘&&read_ca<=‘9‘) read_p=read_p*10+read_ca-48,read_ca=getchar();
    return read_p;
}
const int MOD=998244353,g=3;
inline int mi(int x,int y){
    int mmh=1;
    while (y){
        if (y&1) mmh=1LL*mmh*x%MOD;
        y>>=1;x=1LL*x*x%MOD;
    }
    return mmh;
}
int tot,k,n,m,f[MN],mmh,I[MN],_I[MN],L[MN],R[MN],MMH,N[MN],A[MN],B[MN],e[MN],_e[MN],W[MN],C_a[MN],C_b[MN],N_c[MN],C[MN],D[MN],Q[MN],_A[MN],_B[MN],ANS[MN];
inline void M(int &x){while(x>=MOD)x-=MOD;while(x<0)x+=MOD;}
inline int ask(int n,int k){
    for (int i=1;i<=k+1;i++) N[i]=mi(i,k);
    for (int i=1;i<=k+1;i++) M(N[i]+=N[i-1]);
    n%=MOD;
    for (int i=0;i<=k+1;i++) L[i]=R[i]=n-i;
    for (int i=1;i<=k+1;i++) L[i]=1ll*L[i-1]*L[i]%MOD;
    for (int i=k;i>=0;i--) R[i]=1ll*R[i+1]*R[i]%MOD;
    mmh=0;
    for (int i=0;i<=k+1;i++){
        MMH=N[i];
        if (i>0) MMH=1LL*MMH*_I[i]%MOD*L[i-1]%MOD;
        if (i<k+1) MMH=1LL*MMH*_I[k+1-i]%MOD*((k+1-i)%2?-1:1)*R[i+1]%MOD;
        M(mmh+=MMH);
    }
    return mmh;
}
inline void inv(){
    int base=mi(g,(MOD-1)/tot),_base=mi(base,MOD-2);
    e[0]=_e[0]=1;
    for (int i=1;i<=tot;i++) e[i]=1LL*e[i-1]*base%MOD,_e[i]=1LL*_e[i-1]*_base%MOD;
}
inline void NTT(int N,int a[],int w[]){
    for (int j,i=j=0;i<N;i++){
        if (i>j) swap(a[i],a[j]);
        for (int k=N>>1;(j^=k)<k;k>>=1);
    }
    for (int i=2;i<=N;i<<=1){
        for (int k,j=k=0,s=tot/i;k<(i>>1);j+=s,k++) W[k]=w[j];
        for (int m=i>>1,j=0;j<N;j+=i)
        for (int k=0;k<m;k++){
            int A=j+k,B=A+m,z=1LL*a[B]*W[k]%MOD;
            M(a[B]=a[A]-z);
            M(a[A]+=z);
        }
    }
}
inline void cc(int n,int m,int a[],int b[],int c[]){
    int N=1,i;while (N<(n+m)) N<<=1;
    for (i=0;i<n;i++) C_a[i]=a[i];fill(C_a+n,C_a+N,0);
    for (i=0;i<m;i++) C_b[i]=b[i];fill(C_b+m,C_b+N,0);
    NTT(N,C_a,e);NTT(N,C_b,e);
    for (i=0;i<N;i++) c[i]=1LL*C_a[i]*C_b[i]%MOD;
    NTT(N,c,_e);
    int w=mi(N,MOD-2);
    for (i=0;i<N;i++) c[i]=1LL*c[i]*w%MOD;
}
inline void _D(int n,int a[],int b[]){for (int i=0;i<n;i++) b[i]=1LL*(i+1)*a[i+1]%MOD;b[n]=0;}
inline void _S(int n,int a[],int b[]){for (int i=n;i;i--) b[i]=1LL*a[i-1]*I[i]%MOD;b[0]=0;}
void ny(int n,int a[],int b[]){
    if (n==1) memset(b,0,sizeof(int)*tot),b[0]=mi(a[0],MOD-2);else{
        ny((n+1)>>1,a,b);
        register int i;
        int N=1;while (N<(n<<1)) N<<=1;
        copy(a,a+n,N_c);fill(N_c+n,N_c+N,0);
        NTT(N,N_c,e);NTT(N,b,e);
        for (i=0;i<N;i++) b[i]=(2LL-1LL*N_c[i]*b[i]%MOD+MOD)*b[i]%MOD;
        NTT(N,b,_e);
        int w=mi(N,MOD-2);
        for (i=0;i<n;i++) b[i]=1LL*b[i]*w%MOD;fill(b+n,b+N,0);
    }
}
void sqrt(int n,int a[],int b[]){
    if (n==1) memset(b,0,sizeof(int)*tot),b[0]=int(sqrt(a[0])+0.5);else{
        sqrt((n+1)>>1,a,b);
        register int i;
        int N=1,w=I[2];while (N<(n<<1)) N<<=1;
        copy(b,b+n,D);fill(D+n,D+N,0);
        for (i=0;i<n;i++) M(D[i]<<=1);
        ny(n,D,C);
        cc(n,n,a,C,C);
        for (i=0;i<n;i++) b[i]=(1LL*w*b[i]+C[i])%MOD;
    }
}
inline void Ln(int n,int a[],int b[]){
    memset(C,0,sizeof(int)*tot);memset(D,0,sizeof(int)*tot);
    _D(n,a,D);ny(n,a,C);
    cc(n,n,D,C,b);
    _S(n,b,b);
}
void exp(int n,int a[],int b[]){
    if (n==1) memset(b,0,sizeof(int)*tot),b[0]=1;else{
        exp((n+1)>>1,a,b);
        Ln(n,b,Q);
        int N=1,w=(MOD+1)>>1;while (N<(n<<1)) N<<=1;
        for (int i=0;i<n;i++) M(Q[i]=a[i]-Q[i]);M(Q[0]+=1);
        cc(n,n,Q,b,b);
        fill(b+n,b+N,0);
    }
}
void work(int n,int C[]){
    if (n==0){
        C[0]=1;
        for (int i=1;i<k;i++) C[i]=0;
    }
    for (int i=0;i<k;i++) A[i]=_I[i+1];
    ny(k,A,B);
    for (int i=0;i<k;i++) A[i]=1LL*mi(n+1,i+1)*_I[i+1]%MOD;
    cc(k,k,A,B,C);
}
int main(){
    scanf("%d%d%d",&k,&m,&n);k++;
    for(tot=1;tot<(k<<1);tot<<=1);inv();
    I[1]=1;for (int i=2;i<MN;i++) I[i]=1LL*(MOD-MOD/i)*I[MOD%i]%MOD;
    f[0]=_I[0]=1;for (int i=1;i<MN;i++) _I[i]=1LL*_I[i-1]*I[i]%MOD,f[i]=1LL*f[i-1]*i%MOD;
    //scanf("%d%d%d",&k,&m,&n);
    //n=3;k=10;
    /*for (int i=0;i<=k;i++) S[i]=1LL*ask(n,i)*I[i]%MOD;
    for (int i=0;i<=k;i++){
        int o=0;
        for (int j=0;j<=i;j++) o=(1LL*S[i]*I[j+1]+o)%MOD;
        printf("%d ",o);
    }
    puts("");
    for (int i=0;i<=k;i++)
    printf("%d ",1LL*(mi(n+1,i+1)-1)*I[i+1]%MOD);
    puts("");
    */
    ANS[0]=1;
    for (int i=1;i<=n;i++){
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        work(a-1,_A);work(b,_B);
        //for (int i=0;i<k;i++) printf("%d ",1ll*_B[i]*f[i]%MOD);puts("");
        int tmp=mi(b-a+1,MOD-2);
        for (int i=0;i<k;i++) M(_B[i]-=_A[i]),_B[i]=1LL*_B[i]*tmp%MOD;
        Ln(k,_B,_A);
        for (int i=0;i<k;i++) _A[i]=1LL*_A[i]*c%MOD;
        exp(k,_A,_B);
        cc(k,k,ANS,_B,ANS);
        //for (int i=0;i<k;i++) printf("%d ",1LL*ANS[i]*f[i]);puts("");
    }
    printf("%d\n",1LL*ANS[k-1]*f[k-1]%MOD);
}

原文地址:https://www.cnblogs.com/Enceladus/p/9427389.html

时间: 2024-10-09 22:36:21

July Challenge 2018 : Picking Fruit for Chefs的相关文章

Codechef July Challenge 2014部分题解

Dish Owner(并查集) 链接:http://www.codechef.com/JULY14/problems/DISHOWN/ 题意分析:本题主要操作就是给出0 x y时,拥有第x道菜的厨师与拥有第y道菜的厨师pk,谁拥有的所有菜的其中一道菜(不一定是x或y)的分值比较高谁就获胜,并赢得loser的所有菜.即比较的是每个人分值最高的菜,所以对于非loser的人来说,他的分值最高的菜是不变的.综合题意用并查集易解. #include <cstdio> const int Maxn=100

Codeforces Avito Code Challenge 2018 D. Bookshelves

Codeforces Avito Code Challenge 2018 D. Bookshelves 题目连接: http://codeforces.com/contest/981/problem/D Description Mr Keks is a typical white-collar in Byteland. He has a bookshelf in his office with some books on it, each book has an integer positive

Codechef October Challenge 2018 游记

Codechef October Challenge 2018 游记 CHSERVE - Chef and Serves 题目大意: 乒乓球比赛中,双方每累计得两分就会交换一次发球权. 不过,大厨和小厨用了另外一种规则:双方每累计得 K 分才会交换发球权.比赛开始时,由大厨发球. 给定大厨和小厨的当前得分(分别记为 P1 和 P2),请求出接下来由谁发球. 思路: \((P1+P2)\%K\)判断奇偶性即可. 代码链接 BITOBYT - Byte to Bit 题目大意: 在字节国里有三类居民

June Challenge 2018 Division 2

Naive Chef 暴力 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int main() { 5 int T; 6 scanf("%d", &T); 7 while(T--){ 8 int N, A, B, x, ca = 0, cb = 0; 9 scanf("%d %d %d", &N, &A, &B); 10 for(int i = 1; i <

codechef September Challenge 2018 Division 2 A-F

比赛链接 上紫啦hhh,好开心 每个题里面都有中文翻译,我就不说题意了.. A 直接模拟即可 #include<cstdio> #include<algorithm> #define int long long using namespace std; const int MAXN = 1e5 + 10; inline int read() { char c = getchar(); int x = 0, f = 1; while(c < '0' || c > '9')

[codechef July Challenge 2017] IPC Trainers

IPCTRAIN: 训练营教练题目描述本次印度编程训练营(Indian Programming Camp,IPC)共请到了 N 名教练.训练营的日程安排有 M 天,每天最多上一节课.第 i 名教练在第 Di 天到达,直到训练营结束才离开.第 i 名教练希望上 Ti 节课.要是少上了课,那么教练会感到扎心,每少上一节,扎心值就会加 Si.作为主办方,你希望最小化所有教练的扎心值之和.输入格式输入的第一行包含一个整数 T,代表测试数据的组数.接下来是 T 组数据.每组数据的第一行包含两个整数 N 和

[codechef July Challenge 2017] Chef and Sign Sequences

CHEFSIGN: 大厨与符号序列题目描述大厨昨天捡到了一个奇怪的字符串 s,这是一个仅包含'<'.'='和'>'三种比较符号的字符串.记字符串长度为 N,大厨想要在字符串的开头.结尾,和每两个字符之间插入一个正整数,共N + 1 个数.大厨希望插入数字之后,这些比较符号所表达的含义是正确的.举个例子,如果在'<'前后分别插入 a 和 b,那么应当有 a < b.对于'='和'>'也是类似的.大厨可以在 [1, P] 中任意选择数字插入,同一个数也可以被插入到多个位置.请你帮

[codechef July Challenge 2017] Calculator

CALC: 计算器题目描述大厨有一个计算器,计算器上有两个屏幕和两个按钮.初始时每个屏幕上显示的都是 0.每按一次第一个按钮,就会让第一个屏幕上显示的数字加 1,同时消耗 1 单位的能量.每按一次第二个按钮,会让第二个屏幕上显示的数字加上第一个屏幕上显示的数字,同时消耗 B 单位的能量.初始时,计算器有 N 单位的能量.大厨想知道在能量限制下,第二个屏幕上最大可以出现的数字是多少?输入格式输入的第一行包含一个整数 T,代表测试数据的组数.接下来是 T 组数据.每组数据仅有一行,包含两个整数 N

CodeChef February Challenge 2018 Broken Clock (三角函数推导 + 矩阵快速幂)

题目链接  Broken Clock   中文题面链接 令$cos(xα) = f(x)$ 根据三角函数变换公式有 $f(x) = \frac{2d}{l} f(x-1) - f(x-2)$ 令$f(x) = \frac{g(x)}{l^{x}}$ $\frac{g(x)}{l^{x}} = \frac{2d}{l} * \frac{g(x-1)}{l^{x-1}} - \frac{g(x-2)}{l^{x-2}}$ $g(x) = 2dg(x-1) - l^{2}g(x-2)$ 原文地址:ht