九、十月刷题记录4

2018CCPC桂林 B. Array Modify

题意:
m ( 1 e 9 ) m(1e9) m(1e9)轮操作:
A [ i ] = ( ∑ j = i m i n ( i + L − 1 , n ) A [ j ] ) m o d    P A[i]=(\sum_{j=i}^{min(i+L-1,n)}A[j])\mod P A[i]=(j=imin(i+L1,n)A[j])modP
后的数组。

注意到新数组中 A ′ A' A的值由差值固定的一段 A A A累计得来。
于是每次操作都是一次多项式乘法, C [ x ] = ∑ i = 0 x A [ i ] ∗ B [ x − i ] C[x]=\sum_{i=0}^xA[i]*B[x-i] C[x]=i=0xA[i]B[xi]
考虑构造 B [ x − i ] B[x-i] B[xi]
由式子可知, B [ 0 ] B[0] B[0] B [ L − 1 ] B[L-1] B[L1]这连续一段都是1,其他是0。
而注意到,当 A A A到末尾的时候,由于长度关系,不能由完整的一段长度为L的更新而来。所以考虑将A翻转。
于是我们的A和B就成为了:
[an-1,an-2,…,a4,a3,a2,a1,a0]
[1,1,1,…,1,1,0,0,0,…,0]
结果序列就是:
[an-1, an-2+an-1, an-3+an-2+an-1, …, aL+1+…+a3+a2, aL+…+a2+a1, aL-1+…+a1+a0]
就是想要的结果序列的翻转。
于是问题转化为求 A − 1 × B m A^{-1}\times B^m A1×Bm
多项式快速幂带两个log,说过不了。
那么我们考虑用生成函数简化 B m B^m Bm
注意到 B = 1 + x + x 2 + . . . + x L − 1 B=1+x+x^2+...+x^{L-1} B=1+x+x2+...+xL1
是个等比数列。那么我们改写成 1 − x L 1 − x \frac{1-x^L}{1-x} 1x1xL
现在要求这个东西的 m m m次幂。
发现上下求幂都可以用二项式展开。
也就是分子是 ∑ i = 0 m i n ( n − 1 , m ) ( m i ) ( − 1 ) i x L i \sum_{i=0}^{min(n-1,m)}\binom{m}{i}(-1)^ix^{Li} i=0min(n1,m)(im)(1)ixLi
分母是 ∑ i = 0 m i n ( n − 1 , m ) ( m i ) ( − 1 ) i x i \sum_{i=0}^{min(n-1,m)}\binom{m}{i}(-1)^ix^i i=0min(n1,m)(im)(1)ixi
于是分子分母的幂次都是一个多项式了。
于是将分母求逆即可。

//
// Created by Artist on 2021/10/22.
//

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
#define mkp make_pair
#define fi first
#define se second
#define pb push_back
#define all(x) x.begin(),x.end()
#define DB1(args...) do { cout << #args << " : "; dbg(args); } while (0)
#define endl '\n'

void dbg() { std::cout << "  #\n"; }

template<typename T, typename...Args>
void dbg(T a, Args...args) {
    std::cout << a << ' ';
    dbg(args...);
}

void io() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); }
const int maxn = 1e5+4;
const int mod = 998244353;
const int g = 3;
int A[maxn<<2],B[maxn<<2],C[maxn<<2],C2[maxn<<2],tmp[maxn<<2];

int qpow(int a, int n) {
    int ans=1;
    while(n) {
        if(n&1) ans=1ll*ans*a%mod;
        a=1ll*a*a%mod;
        n>>=1;
    }
    return ans;
}
int rev[maxn<<2];
void ntt(int *a,int n,int t) {
    for(int i=1;i<n;++i) {
        rev[i] = (rev[i>>1]>>1)|(i&1?n>>1:0);
        if(i>rev[i]) swap(a[i],a[rev[i]]);
    }
    for(int i=2;i<=n;i<<=1) {
        int wn=qpow(g,(mod-1)/i);
        if(t==-1) wn=qpow(wn,mod-2);
        for(int j=0;j<n;j+=i) {
            int w=1;
            for(int k=j;k<j+i/2;++k) {
                int u=a[k];
                int v=1ll*a[k+i/2]*w%mod;
                a[k]=(1ll*u+v)%mod;
                a[k+i/2]=(1ll*u-v+mod)%mod;
                w=1ll*w*wn%mod;
            }
        }
    }
    if(t==-1) {
        ll inv=qpow(n,mod-2);
        for(int i=0;i<n;++i) a[i]=1ll*a[i]*inv%mod;
    }
}

void polyinv(int f[],int h[],int n) {
    fill(f,f+n+n,0);
    f[0] = qpow(h[0],mod-2);
    for(int t=2;t<=n;t<<=1) {
        const int t2=t<<1;
        copy(h,h+t,tmp);
        fill(tmp+t,tmp+t2,0);

        ntt(f,t2,1);
        ntt(tmp,t2,1);
        for(int i=0;i!=t2;++i)
            f[i]=1ll*f[i]*(2-1ll*f[i]*tmp[i]%mod+mod)%mod;
        ntt(f,t2,-1);

        fill(f+t,f+t2,0);
    }
}

signed main() {
    io();
    int ca=0;
    int t;cin>>t;
    while(t--) {
        int n,m,L;cin>>n>>L>>m;
        int lim;
        for(lim=1;lim<(n<<1);lim<<=1);
        for(int i=0;i<lim;++i) A[i]=B[i]=C[i]=0;
        for(int i=0;i<n;++i) cin>>tmp[i];
        for(int i=0;i<n;++i) A[i]=tmp[n-i-1];
        for(int i=0,c=1,f=1;i<=m&&1ll*i*L<n;++i) {
            B[i*L]=1ll*c*f%mod;
            c=1ll*c*(m-i)%mod*qpow(i+1,mod-2)%mod;
            f=mod-f;
        }
        for(int i=0,c=1,f=1;i<=m&&i<n;++i) {
            C[i]=1ll*c*f%mod;
            c=1ll*c*(m-i)%mod*qpow(i+1,mod-2)%mod;
            f=mod-f;
        }
        int len;
        for(len=1;len<n;len<<=1);
        polyinv(C2,C,len);
        ntt(B,lim,1);
        ntt(C2,lim,1);
        ntt(A,lim,1);
        for(int i=0;i<lim;++i) B[i]=1ll*B[i]*C2[i]%mod;
        ntt(B,lim,-1);
        fill(B+len,B+len+len,0); // 必须清空(取模),不然会错,调了很久这里
        ntt(B,lim,1);
        for(int i=0;i<lim;++i) B[i]=1ll*B[i]*A[i]%mod;
        ntt(B,lim,-1);
        cout<<"Case "<<++ca<<": ";
        for(int i=n-1;~i;--i) cout<<B[i]<<" ";
        cout<<endl;
    }
}

多项式快速幂板子

多项式快速幂加强版

B ( x ) ≡ A ( x ) k m o d    P B(x)\equiv A(x)^k\mod P B(x)A(x)kmodP k ∈ 1 0 1 0 5 k\in 10^{10^5} k10105
不能快速幂,因为这个 k k k不是模 P − 1 P-1 P1意义下。
B ( x ) ≡ A ( x ) k m o d    P B(x)\equiv A(x)^k\mod P B(x)A(x)kmodP
B ( x ) ≡ e k ln ⁡ A ( x ) m o d    P B(x)\equiv e^{k\ln A(x)}\mod P B(x)eklnA(x)modP
所以先对 A ( x ) A(x) A(x)进行模 P P P意义下的对数,再乘上模 P P P意义下的 k k k,再求指数。
以上做法的前提条件是 A [ 0 ] = 1 A[0]=1 A[0]=1,因为取对数需要这样。
在加强版中,这个条件不满足。
发现 A k = ( A A [ 0 ] ) k × A [ 0 ] k A^k=(\frac{A}{A[0]})^k\times A[0]^k Ak=(A[0]A)k×A[0]k
因为 A [ 0 ] A[0] A[0]是个常数,所以后面的 A [ 0 ] k A[0]^k A[0]k k k k要欧拉降幂。括号内多项式幂次的不用,像普通版那样算就行。
如果 A [ 0 ] = = 0 A[0]==0 A[0]==0这个做法就挂了。
发现 A k = ( A x t ) k × x t k A^k=(\frac{A}{x^t})^k\times x^{tk} Ak=(xtA)k×xtk
所以把多项式 A A A左移掉那些系数为0的项。最后再右移上 t k tk tk项即可。

普通版:

//
// Created by Artist on 2021/10/23.
//

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
#define mkp make_pair
#define fi first
#define se second
#define pb push_back
#define all(x) x.begin(),x.end()
#define DB1(args...) do { cout << #args << " : "; dbg(args); } while (0)
#define endl '\n'
#define reg register

void dbg() { std::cout << "  #\n"; }

template<typename T, typename...Args>
void dbg(T a, Args...args) {
    std::cout << a << ' ';
    dbg(args...);
}

void io() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); }
const int maxn = 1e5+5;
const int P = 998244353;
const int g = 3;
string s;

inline int read() {
    reg char ch=getchar();
    reg int x=0,f=1;
    while(ch<'0'||ch>'9') {
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(isdigit(ch)) {
        x=(x<<3)+(x<<1)+ch-'0';
        ch=getchar();
    }
    return x*f;
}

inline int readm() {
    reg char ch=getchar();
    reg ll x=0,f=1;
    while(ch<'0'||ch>'9') {
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9') {
        x=((x<<3)+(x<<1)+ch-'0')%P;
        ch=getchar();
    }
    return x*f;
}


inline int qpow(int a,int n) {
    int ans=1;
    while(n) {
        if(n&1) ans=1ll*ans*a%P;
        a=1ll*a*a%P;
        n>>=1;
    }
    return ans;
}

void ntt(int a[],int n,int t) {
    static int rev[maxn<<2];
    for(int i=1;i<n;++i) {
        rev[i] = (rev[i>>1]>>1)|(i&1?n>>1:0);
        if(i>rev[i]) swap(a[i],a[rev[i]]);
    }
    for(int i=2;i<=n;i<<=1) {
        int wn=qpow(g,(P-1)/i);
        if(t==-1) wn=qpow(wn,P-2);
        for(int j=0;j<n;j+=i) {
            int w=1;
            for(int k=j;k<j+i/2;++k) {
                int u=a[k];
                int v=1ll*a[k+i/2]*w%P;
                a[k]=(1ll*u+v)%P;
                a[k+i/2]=(1ll*u-v+P)%P;
                w=1ll*w*wn%P;
            }
        }
    }
    if(t==-1) {
        ll inv=qpow(n,P-2);
        for(int i=0;i<n;++i) a[i]=1ll*a[i]*inv%P;
    }
}

void polyinv(int f[],int h[],int n) {
    static int tmp[maxn<<2];
    int len;
    for(len=1;len<n;len<<=1);
    fill(f,f+len+len+2,0);
    fill(tmp,tmp+len+1,0);
    f[0] = qpow(h[0],P-2);
    for(int t=2;t<=len;t<<=1) {
        const int t2=t<<1;
        copy(h,h+t,tmp);
        fill(tmp+t,tmp+t2,0);
        ntt(f,t2,1);
        ntt(tmp,t2,1);
        for(int i=0;i!=t2;++i)
            f[i]=1ll*f[i]*(2-1ll*f[i]*tmp[i]%P+P)%P;
        ntt(f,t2,-1);
        fill(f+t,f+t2,0);
    }
    fill(f+n,f+len+1,0);
}

void polyln(int f[],int h[],int n) {
    static int tmp2[maxn<<2],tmp3[maxn<<2];
    int lim;
    for(lim=1;lim<(n<<1);lim<<=1);
    fill(tmp2,tmp2+lim,0);
    fill(tmp3,tmp3+lim,0);
    fill(f,f+lim,0);
    polyinv(tmp3,h,n);
    for(int i=1;i<n;++i) tmp2[i-1]=1ll*h[i]*i%P;
    ntt(tmp2,lim,1);
    ntt(tmp3,lim,1);
    for(int i=0;i<lim;++i) tmp3[i]=1ll*tmp3[i]*tmp2[i]%P;
    ntt(tmp3,lim,-1);
    for(int i=1;i<n;++i) f[i]=1ll*qpow(i,P-2)*tmp3[i-1]%P;
    fill(f+n,f+lim,0);
}

void polyexp(int f[],int h[],int n) {
    static int tmp4[maxn<<2];
    if(n==1) {f[0]=1;return;}
    int lim;
    for(lim=1;lim<(n<<1);lim<<=1);
    fill(tmp4,tmp4+lim,0);
    polyexp(f,h,n+1>>1),polyln(tmp4,f,n);
    tmp4[0]=(1ll*h[0]+1-tmp4[0]+P)%P;
    for(int i=1;i<n;++i) tmp4[i]=(1ll*h[i]-tmp4[i]+P)%P;
    ntt(tmp4,lim,1),ntt(f,lim,1);
    for(int i=0;i<lim;++i) f[i]=1ll*f[i]*tmp4[i]%P;
    ntt(f,lim,-1);
    fill(f+n,f+lim,0);
}

int A[maxn<<2],B[maxn<<2],C[maxn<<2];
signed main() {
    int n=read(),k=readm();
    for(int i=0;i<n;++i) A[i]=read();
    polyln(B,A,n);
    for(int i=0;i<n;++i) B[i]=1ll*B[i]*k%P;
    polyexp(C,B,n);
    for(int i=0;i<n;++i) printf("%d ",C[i]);
}

加强版:

//
// Created by Artist on 2021/10/23.
//

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
#define mkp make_pair
#define fi first
#define se second
#define pb push_back
#define all(x) x.begin(),x.end()
#define DB1(args...) do { cout << #args << " : "; dbg(args); } while (0)
#define endl '\n'
#define reg register

void dbg() { std::cout << "  #\n"; }

template<typename T, typename...Args>
void dbg(T a, Args...args) {
    std::cout << a << ' ';
    dbg(args...);
}

void io() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); }
const int maxn = 1e5+5;
const int P = 998244353;
const int g = 3;

inline int read() {
    reg char ch=getchar();
    reg int x=0,f=1;
    while(ch<'0'||ch>'9') {
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(isdigit(ch)) {
        x=(x<<3)+(x<<1)+ch-'0';
        ch=getchar();
    }
    return x*f;
}

inline int qpow(int a,int n) {
    int ans=1;
    while(n) {
        if(n&1) ans=1ll*ans*a%P;
        a=1ll*a*a%P;
        n>>=1;
    }
    return ans;
}

void ntt(int a[],int n,int t) {
    static int rev[maxn<<2];
    for(int i=1;i<n;++i) {
        rev[i] = (rev[i>>1]>>1)|(i&1?n>>1:0);
        if(i>rev[i]) swap(a[i],a[rev[i]]);
    }
    for(int i=2;i<=n;i<<=1) {
        int wn=qpow(g,(P-1)/i);
        if(t==-1) wn=qpow(wn,P-2);
        for(int j=0;j<n;j+=i) {
            int w=1;
            for(int k=j;k<j+i/2;++k) {
                int u=a[k];
                int v=1ll*a[k+i/2]*w%P;
                a[k]=(1ll*u+v)%P;
                a[k+i/2]=(1ll*u-v+P)%P;
                w=1ll*w*wn%P;
            }
        }
    }
    if(t==-1) {
        ll inv=qpow(n,P-2);
        for(int i=0;i<n;++i) a[i]=1ll*a[i]*inv%P;
    }
}

void polyinv(int f[],int h[],int n) {
    static int tmp[maxn<<2];
    int len;
    for(len=1;len<n;len<<=1);
    fill(f,f+len+len+2,0);
    fill(tmp,tmp+len+1,0);
    f[0] = qpow(h[0],P-2);
    for(int t=2;t<=len;t<<=1) {
        const int t2=t<<1;
        copy(h,h+t,tmp);
        fill(tmp+t,tmp+t2,0);
        ntt(f,t2,1);
        ntt(tmp,t2,1);
        for(int i=0;i!=t2;++i)
            f[i]=1ll*f[i]*(2-1ll*f[i]*tmp[i]%P+P)%P;
        ntt(f,t2,-1);
        fill(f+t,f+t2,0);
    }
    fill(f+n,f+len+1,0);
}

void polyln(int f[],int h[],int n) {
    static int tmp2[maxn<<2],tmp3[maxn<<2];
    int lim;
    for(lim=1;lim<(n<<1);lim<<=1);
    fill(tmp2,tmp2+lim,0);
    fill(tmp3,tmp3+lim,0);
    fill(f,f+lim,0);
    polyinv(tmp3,h,n);
    for(int i=1;i<n;++i) tmp2[i-1]=1ll*h[i]*i%P;
    ntt(tmp2,lim,1);
    ntt(tmp3,lim,1);
    for(int i=0;i<lim;++i) tmp3[i]=1ll*tmp3[i]*tmp2[i]%P;
    ntt(tmp3,lim,-1);
    for(int i=1;i<n;++i) f[i]=1ll*qpow(i,P-2)*tmp3[i-1]%P;
    fill(f+n,f+lim,0);
}

void polyexp(int f[],int h[],int n) {
    static int tmp4[maxn<<2];
    if(n==1) {f[0]=1;return;}
    int lim;
    for(lim=1;lim<(n<<1);lim<<=1);
    fill(tmp4,tmp4+lim,0);
    polyexp(f,h,n+1>>1),polyln(tmp4,f,n);
    tmp4[0]=(1ll*h[0]+1-tmp4[0]+P)%P;
    for(int i=1;i<n;++i) tmp4[i]=(1ll*h[i]-tmp4[i]+P)%P;
    ntt(tmp4,lim,1),ntt(f,lim,1);
    for(int i=0;i<lim;++i) f[i]=1ll*f[i]*tmp4[i]%P;
    ntt(f,lim,-1);
    fill(f+n,f+lim,0);
}

int A[maxn<<2],B[maxn<<2],C[maxn<<2];
string s;

signed main() {
    int n=read();
    int k1=0,k2=0,k3=0;cin>>s;
    for(int i=0;i<s.length();++i) {
        k1=(10ll*k1+s[i]-'0')%P;
        k2=(10ll*k2+s[i]-'0')%(P-1);
        if(i<6) k3=10*k3+s[i]-'0';
    }
    int pos=-1,a0;
    for(int i=0;i<n;++i) {
        A[i]=read();
        if(pos==-1&&A[i]) {
            a0=A[i];
            pos=i;
        }
    }
    // 只有A[0]==0的时候才需要转移,不然不用转移
    // A[0]!=1的时候需要除以A[0],最后再乘回A[0]^{k mod P-1}

    // 全为0
    if(pos==-1) {
        for(int i=0;i<n;++i) printf("0 ");
        return 0;
    }

    // 左移
    for(int i=0;i<n;++i) {
        if(i+pos<n) A[i]=A[i+pos];
        else A[i]=0; // 移完后清空
    }

    // 除掉A[0]
    int a0inv = qpow(a0,P-2);
    for(int i=0;i<n;++i) A[i]=1ll*A[i]*a0inv%P;

    polyln(B,A,n);
    for(int i=0;i<n;++i) B[i]=1ll*B[i]*k1%P;
    polyexp(C,B,n);

    // 右移
    int dis=min(1ll*n,1ll*k3*pos);
    for(int i=n-1;~i;--i) {
        if(i-dis>=0) C[i]=C[i-dis];
        else C[i]=0;
    }
    int mul = qpow(a0,k2);
    for(int i=0;i<n;++i) C[i]=1ll*C[i]*mul%P;
    for(int i=0;i<n;++i) printf("%d ",C[i]);
}

2017CCPC女生赛 Innumerable Ancestors

树剖+树上倍增
把A的节点的祖先全部标记,对每个B查询其祖先中最深的有标记的,返回这个深度。
然后还原树,把A删掉,等待下次样例。
因为cinTLE了两次-。-

//
// Created by artist on 2021/10/23.
//


#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
#define mkp make_pair
#define fi first
#define se second
#define pb push_back
#define all(x) x.begin(),x.end()
#define DB1(args...) do { cout << #args << " : "; dbg(args); } while (0)
#define endl '\n'
#define pii pair<int,int>
#define int long long
void dbg() { std::cout << "  #\n"; }

template<typename T, typename...Args>
void dbg(T a, Args...args) {
    std::cout << a << ' ';
    dbg(args...);
}

void io() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); }
int n,m;
const int maxn = 1e5+5;
vector<int> G[maxn];
int f[24][maxn];
int sz[maxn],dfn,son[maxn],tp[maxn],num[maxn],dep[maxn];
int tr[maxn<<2],lzy[maxn<<2];

int ql,qr,opt;

void dfs0(int u,int fa) {
    sz[u]=1;
    dep[u]=dep[fa]+1;
    for(auto v:G[u]) {
        if(v-fa) {
            dfs0(v,u),sz[u]+=sz[v];
            if(sz[v]>sz[son[u]]) son[u]=v;
        }
    }
}

void dfs1(int u,int pa,int fa) {
    num[u]=++dfn;
    tp[u]=pa;
    f[0][u]=fa;
    if(son[u]) dfs1(son[u],pa,u);
    for(auto v:G[u]) if(v-fa&&v-son[u]) dfs1(v,v,u);
}

void build(int l,int r,int rt) {
    if(l==r) {
        tr[rt] = lzy[rt] = 0;
        return;
    }
    int mid=l+r>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    tr[rt] = lzy[rt] = 0;
}

int query(int l,int r,int rt) {
    if(l==r) {
        return tr[rt];
    }
    int mid=l+r>>1;
    if(lzy[rt]) {
        lzy[rt<<1]+=lzy[rt];
        lzy[rt<<1|1]+=lzy[rt];
        tr[rt<<1]+=lzy[rt]*(mid-l+1);
        tr[rt<<1|1]+=lzy[rt]*(r-mid);
        lzy[rt]=0;
    }
    if(ql<=mid) return query(l,mid,rt<<1);
    else return query(mid+1,r,rt<<1|1);
}

void add(int l,int r,int rt) {
    if(ql<=l&&qr>=r) {
        tr[rt]+=opt*(r-l+1);
        lzy[rt]+=opt;
        return;
    }
    int mid=l+r>>1;
    if(lzy[rt]) {
        lzy[rt<<1]+=lzy[rt];
        lzy[rt<<1|1]+=lzy[rt];
        tr[rt<<1]+=lzy[rt]*(mid-l+1);
        tr[rt<<1|1]+=lzy[rt]*(r-mid);
        lzy[rt]=0;
    }
    if(ql<=mid) add(l,mid,rt<<1);
    if(qr>mid) add(mid+1,r,rt<<1|1);
    tr[rt]=tr[rt<<1]+tr[rt<<1|1];
}

int a[maxn],b[maxn];

// 检测这个点是否有值
bool check(int u) {
    ql=num[u];
    if(query(1,n,1)) return 1;
    else return 0;
}

int solve(int u) {
    if(check(u)) return dep[u];
    for(int j=20;~j;--j)
        if(f[j][u]&&!check(f[j][u])) u=f[j][u];
    return dep[f[0][u]];
}

signed main() {
    while(~scanf("%lld",&n)) {
        scanf("%lld",&m);
        for(int i=1;i<=n;++i) G[i].clear();
        for(int i=1;i<=n;++i) son[i]=0;
        dfn=0;
        for(int i=1;i<n;++i) {
            int u,v;scanf("%lld%lld",&u,&v);
            G[u].pb(v);
            G[v].pb(u);
        }
        dfs0(1,0);
        dfs1(1,1,0);
        for(int j=1;j<=20;++j) for(int i=1;i<=n;++i) f[j][i] = f[j-1][f[j-1][i]];
        build(1,n,1);
        while(m--) {
            int k1;scanf("%lld",&k1);
            opt=1;
            for(int i=1;i<=k1;++i) {
                scanf("%lld",&a[i]);
                int u=a[i];
                while(u) {
                    ql=num[tp[u]],qr=num[u];
                    add(1,n,1);
                    u = f[0][tp[u]];
                }
            }
            int k2;scanf("%lld",&k2);
            int ret=0;
            for(int i=1;i<=k2;++i) {
                scanf("%lld",&b[i]);
                ret = max(ret,solve(b[i]));
            }
            opt=-1;
            for(int i=1;i<=k1;++i) {
                int u=a[i];
                while(u) {
                    ql=num[tp[u]],qr=num[u];
                    add(1,n,1);
                    u = f[0][tp[u]];
                }
            }
            printf("%lld\n",ret);
        }
    }
}

莫比乌斯反演及变形

公式:
f ( n ) = ∑ d ∣ n g ( d ) f(n)=\sum_{d|n}g(d) f(n)=dng(d)
g ( n ) = ∑ d ∣ n f ( n d ) ∗ μ ( d ) g(n)=\sum_{d|n}f(\frac{n}{d})*\mu(d) g(n)=dnf(dn)μ(d)
变形:
倍数和
写法1:
f ( i ) = ∑ d = 1 ⌊ n i ⌋ g ( d ∗ i ) f(i)=\sum_{d=1}^{\lfloor\frac{n}{i}\rfloor}g(d*i) f(i)=d=1ing(di)
g ( i ) = ∑ d = 1 ⌊ n i ⌋ f ( d ∗ i ) μ ( d ) g(i)=\sum_{d=1}^{\lfloor\frac{n}{i}\rfloor}f(d*i)\mu(d) g(i)=d=1inf(di)μ(d)
写法2:
f ( i ) = ∑ i ∣ d , d ≤ n g ( d ) f(i)=\sum_{i|d,d\leq n}g(d) f(i)=id,dng(d)
g ( i ) = ∑ i ∣ d , d ≤ n f ( d ) μ ( d i ) g(i)=\sum_{i|d,d\leq n}f(d)\mu(\frac{d}{i}) g(i)=id,dnf(d)μ(id)

数论分块:
首先有一性质
⌊ n k d ⌋ = ⌊ ⌊ n k ⌋ d ⌋ \lfloor\frac{n}{kd}\rfloor=\lfloor \frac{\lfloor \frac{n}{k}\rfloor}{d}\rfloor kdn=dkn
在这里插入图片描述
在这里插入图片描述

2017 CCPC女生赛 Judicious Strategy

博弈(SG)+爆搜
算是第二次接触这种题,这下该会了吧。。

//
// Created by Artist on 2021/10/25.
//

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
#define mkp make_pair
#define fi first
#define se second
#define pb push_back
#define all(x) x.begin(),x.end()
#define DB1(args...) do { cout << #args << " : "; dbg(args); } while (0)
#define endl '\n'

void dbg() { std::cout << "  #\n"; }

template<typename T, typename...Args>
void dbg(T a, Args...args) {
    std::cout << a << ' ';
    dbg(args...);
}

void io() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); }
const int maxn = 30000;
const int inf = 2e9;

struct SG {
    int wintag,myscore,opscore;
    SG(int a=1,int b=inf,int c=0):wintag(a),myscore(b),opscore(c){}
    bool operator < (const SG &b) const {
        if(wintag!=b.wintag) return wintag<b.wintag;
        if(opscore!=b.opscore) return opscore>b.opscore;
        return myscore<b.myscore;
    }
}sg[maxn];

int n,tot;
string input[33];
unordered_map<string,int> ok;
string reok[maxn];
int score[maxn];
vector<int> G[maxn];


void init() {
    tot = 0;
    ok.clear();
    for(int i=0;i<maxn;++i) {
        G[i].clear();
        sg[i].wintag = -1;
    }
}

int get_score(string tt) {
    int maxx=0,sum=0,len=tt.length(),occ=0;
    for(int i=0;i<len;++i) {
        sum += tt[i]-'a'+1;
        maxx = max(maxx,tt[i]-'a'+1);
    }
    for(int i=1;i<=n;++i) {
        if(input[i].find(tt)!=string::npos) occ++;
    }
    return maxx*sum+occ;
}

void readin() {
    for(int i=1;i<=n;++i) cin>>input[i];
    for(int i=1;i<=n;++i) {
        int len=input[i].length();
        for(int j=0;j<len;++j) {
            string temp = "";
            for(int k=j;k<len;++k) {
                temp += input[i][k];
                if(ok[temp]) continue;
                ok[temp] = ++tot;
                reok[tot] = temp;
                score[tot] = get_score(temp);
            }
        }
    }
}

void build_graph() {
    for(int i=1;i<=tot;++i) {
        int len=reok[i].length();
        if(len==1) {
            G[0].pb(i);
            continue;
        }
        string temp1 = reok[i].substr(1,len-1);
        if(ok[temp1]) G[ok[temp1]].pb(i);
        string temp2 = reok[i].substr(0,len-1);
        if(ok[temp2]) G[ok[temp2]].pb(i);
    }
}

SG dfs(int now) {
    if(sg[now].wintag!=-1) return sg[now];
    if(!G[now].size()) return sg[now]=SG(0,0,score[now]);
    SG worst;
    for(int i=0;i<G[now].size();++i) {
        SG nex=dfs(G[now][i]);
        if(nex<worst) worst=nex;
    }
    return sg[now]=SG(worst.wintag^1,worst.opscore,worst.myscore+score[now]);
}

signed main() {
    while(~scanf("%d",&n)) {
        init();
        readin();
        build_graph();
        SG ans = dfs(0);
        if(ans.wintag) printf("Alice\n");
        else printf("Bob\n");
        printf("%d %d\n",ans.myscore,ans.opscore);
    }
}

2019CCPC哈尔滨 E. Exchanging Gifts

用超级快读就过了的一道题,非常卡常

#include <bits/stdc++.h>
//#define endl '\n'
#define lose {printf("NO\n");return;}
#define win {printf("YES\n");return;}
#define all(A) (A).begin(),(A).end()
#define FOR(I, A, B) for (int I = (A); I <= (B); ++I)
#define PER(I, A, B) for (int I = (A); I >= (B); --I)
#define DB(A) cout<<(A)<<endl
#define lson k*2
#define rson k*2+1
#define fi first
#define se second
#define PB push_back
#define Pair pair<int,int>
#define MP make_pair
#define ll long long
#define ull unsigned long long
//#define int ll
using namespace std;
#define DB1(args...) do { cout << #args << " : "; dbg(args); } while (0)
void dbg() { std::cout << "  #\n"; }
template<typename T, typename...Args>
void dbg(T a, Args...args) { std::cout << a << ' '; dbg(args...); }

template <typename T> void print(T x) {
    if (x < 0) { putchar('-'); print(x); return ; }
    if (x >= 10) print(x / 10);
    putchar((x % 10) + '0');
}

//var
const int maxn=2e6+10;
//head
int n;
int typ[maxn];
vector<int> oper[maxn];
int son[maxn][2];
bool vis[maxn];
int ru[maxn];
ll val[maxn];
int cnt;
unordered_map<int,int> mp2;
ll summ[maxn];
queue<int>q;

#define getcha() (S==T&&(T=(S=fsr)+fread(fsr,1,1<<15,stdin),S==T)?EOF:*S++)
char fsr[1<<15],*S=fsr,*T=fsr;
inline int read(){
    int r(0),w(1);char ch=getcha();
    while(ch>=58 || ch<=47){
        w=(ch=='-'?-1:1);r=(r<<3)+(r<<1)+ch-48;
        ch=getcha();
    }
    while(ch<=57 && ch>=48){
        r=(r<<3)+(r<<1)+ch-48;
        ch=getcha();
    }
    return r*w;
}

void bfs1()
{
    FOR(i,1,n) vis[i]=0;
    vis[n]=1;
    q.push(n);
    while (!q.empty())
    {
        int now=q.front();q.pop();
        if(son[now][0]==0) continue;
        for(int i=0;i<2;++i) {
            int to=son[now][i];
            if (!vis[to])//only visit each node once
            {
                vis[to]=1;
                q.push(to);
            }
        }
    }
    //rebuild
    FOR(i,1,n) son[i][0]=son[i][1]=0;
    FOR(i,1,n) if (vis[i])//truly useful
        {
            if (typ[i]==2)
            {
                son[i][0]=oper[i][0];
                ru[oper[i][0]]++;
                son[i][1]=oper[i][1];
                ru[oper[i][1]]++;
            }
        }
}

void topu()
{
    q.push(n);
    val[n]=1;
    while (!q.empty())
    {
        int now=q.front();q.pop();
        if(son[now][0]==0) continue;
        for(int i=0;i<2;++i) {
            int to=son[now][i];
            ru[to]--;
            val[to]+=val[now];
            if (!ru[to])
            {
                q.push(to);
            }
        }
    }
}

void solve()
{
    n=read();
    FOR(i,1,n)
    {
        oper[i].clear();
        son[i][0]=son[i][1]=0;
        ru[i]=0;
        vis[i]=0;
        val[i]=0;
        summ[i]=0;
    }
    mp2.clear();
    cnt=0;

    FOR(i,1,n)
    {
        int op;
        op=read();
        typ[i]=op;//record type
        if (op==1)
        {
            int k=read();
            FOR(j,1,k)
            {
                int x=read();
                if(!mp2[x]) mp2[x]=++cnt;
                oper[i].PB(mp2[x]);//record reading info
            }
        }
        else
        {
            int x=read(),y=read();
            oper[i].PB(x);//record reading info
            oper[i].PB(y);
            son[i][0]=x;
            son[i][1]=y;
        }
    }


    bfs1();
    topu();
    FOR(i,1,n) if (typ[i]==1&&vis[i])
        {
            for (auto ele : oper[i])
            {
                summ[ele] += val[i];
            }
        }
    ll sum=0;
    ll maxx=0;
    for(int i=1;i<=cnt;++i) {
        sum += summ[i];
        maxx = max(maxx,summ[i]);
    }
    ll ans;
    if (maxx>sum/2)
    {
        ans=sum-maxx+sum-maxx;
    }
    else
    {
        ans=sum;
    }
    printf("%lld\n",ans);
}
signed main()
{
    // freopen("read.txt", "r", stdin);
    // freopen("ans.txt", "w", stdout);
    int TestCase = read();
    while (TestCase--)
    {
        solve();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值