其他分享
首页 > 其他分享> > 9.1

9.1

作者:互联网

小\(trick\)

求\((ax+b)\)的\(DFT\)不需要\(O(nlogn)\)

考虑这个多项式\(\{b,a,0,0,0,0,…\}\)

\(b\)的下标二进制为\((000000)_2\)

\(a\)的下标二进制为\((000001)_2\)

\(a\)的下标翻转后为\((100000)_2\)

也就是除了最后一次\(DFT\),两个数之间不会产生交集。

在最后一次\(DFT\)之前,最高位\(0\)开头的位置都变成了\(b\),最高位\(1\)开头的位置都变成了\(a\)

所以直接把数组前\(\frac{n}{2}\)项赋值成\(b\),后\(\frac{n}{2}\)赋值成\(a\),然后\(O(n)\)做最后一次\(DFT\)就行

inline void NTT(int *F)
{
    for(int i=0; i<(N>>1); ++i) F[i]=F[0];
    for(int i=(N>>1); i<N; ++i) F[i]=F[N>>1];
    int w0=1,w=qp(3,998244352/N);
	for(int i=0; i<(N>>1); ++i)
    {
        int x=F[i],y=calc(1ull*w0*F[i+(N>>1)]);
        ((F[i]=x+y)>=p)&&(F[i]-=p),
        ((F[i+(N>>1)]=x-y)<0)&&(F[i+(N>>1)]+=p),
        w0=calc(1ull*w0*w);
    }
}

CF1613F

题意:

给一棵树,把节点变成一个\(1\sim n\)的排列,要求不能存在父节点比子节点大一,有多少种可能的方案?

\(n\leq 250000\)

题解:

正常不好做,考虑容斥,求\(g_i\)表示至少有\(i\)个不满足要求的对数的情况,然后用二项式反演容斥出来

一个节点最多和一个子节点凑成一对,因为是排列。

如果点\(u\)有\(d_u\)个孩子,那么就贡献\((d_ux+1)\)表示选一个儿子凑一对或者不选。

直接分治\(NTT\)就可以做到\(O(nlog^2n)\)

这里有\(O(nlogn)\)的解法

对于所有相同的\(d_u\),假如有\(c_t\)个,\((d_ux+1)^{c_t}\)用二项式定理直接展开。

其中\(c_t=\sum_u[d_u==t]\)

直接合并复杂度是

\(O(\sum_{i=1}^n\sum_{j=1}^iC_jlog_n)=O(\sum_{i=1}^{n}(n-i+1)C_ilogn)\)

如果倒过来枚举,每个\(C_i\)要乘的就变成了比自己大的部分,

\(O(\sum_{i=1}^n\sum_{j=i}^nC_jlogn)=O(\sum_{i=1}^ni*C_ilogn)=O(nlogn)\)

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define double long double
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define lowbit(i) ((i)&(-i))
#define eps (1e-15)
    const int N=1e6+10,mod=998244353,inf=2e15;
    void __init(int n=2000) {}
    namespace NTT
    {
        const int g=3,gi=332748118;
        int limit=1,len;
        int pos[N];
        inline int fast(int x,int k)
        {
            int ret=1;
            while(k)
            {
                if(k&1) ret=ret*x%mod;
                x=x*x%mod;
                k>>=1;
            }
            return ret;
        }
        inline vector<int> ntt(vector<int> a,int inv)
        {
            for(int i=0;i<limit;++i)
                if(i<pos[i]) swap(a[i],a[pos[i]]);
            for(int mid=1;mid<limit;mid<<=1)
            {
                int Wn=fast(inv?g:gi,(mod-1)/(mid<<1));
                for(int r=mid<<1,j=0;j<limit;j+=r)
                {
                    int w=1;
                    for(int k=0;k<mid;++k,w=w*Wn%mod)
                    {
                        int x=a[j+k],y=w*a[j+k+mid]%mod;
                        a[j+k]=(x+y)%mod;
                        a[j+k+mid]=(x-y+mod)%mod;
                    }
                }
            }
            if(inv) return a;
            inv=fast(limit,mod-2);
            for(int i=0;i<limit;++i) a[i]=a[i]*inv%mod;
            return a;
        }
        inline vector<int> deriva(vector<int> a,int n)
        {
            a.resize(n);
            for(int i=1;i<n;++i) a[i-1]=a[i]*i%mod;
            a[n-1]=0;
            return a;
        }
        inline vector<int> integral(vector<int> a,int n)
        {
            a.resize(n);
            for(int i=n-1;i;--i) a[i]=a[i-1]*fast(i,mod-2)%mod;
            a[0]=0;
            return a;
        }
        inline vector<int> add(vector<int> a,vector<int> b,int n,int m)
        {
            limit=max(n,m);
            a.resize(limit),b.resize(limit);
            for(int i=0;i<limit;++i) a[i]=(a[i]+b[i])%mod;
            return a;
        }
        inline vector<int> mul(vector<int> a,vector<int> b,int n=-1,int m=-1)
        {
            if(n==-1) n=a.size();
            if(m==-1) m=b.size();
            limit=1,len=0;
            while(limit<n+m) limit<<=1,++len;
            a.resize(limit,0),b.resize(limit,0);
            for(int i=0;i<limit;++i) pos[i]=(pos[i>>1]>>1)|((i&1)<<(len-1));
            a=ntt(a,1),b=ntt(b,1);
            for(int i=0;i<limit;++i) a[i]=a[i]*b[i]%mod;
            vector<int> c=ntt(a,0);
            c.resize(n+m-1);
            return c;
        }
        inline vector<int> poly_inv(vector<int> a,int n)
        {
            if(n==1)
            {
                vector<int> b(1);
                b[0]=fast(a[0],mod-2);
                return b;
            }
            vector<int> b=poly_inv(a,(n+1)>>1);
            limit=1,len=0;
            while(limit<n+n) limit<<=1,++len;
            for(int i=0;i<limit;++i) pos[i]=(pos[i>>1]>>1)|((i&1)<<(len-1));
            a.resize(limit),b.resize(limit);
            vector<int> c;
            c.resize(limit);
            for(int i=0;i<n;++i) c[i]=a[i];
            for(int i=n;i<limit;++i) c[i]=b[i]=0;
            c=ntt(c,1);b=ntt(b,1);
            for(int i=0;i<limit;++i) b[i]=(2-c[i]*b[i]%mod+mod)%mod*b[i]%mod;
            b=ntt(b,0);
            b.resize(n);
            return b;
        }
        inline vector<int> ln(vector<int> a,int n)
        {
            return integral(mul(deriva(a,n),poly_inv(a,n),n,n),n);
        }
        inline vector<int> exp(vector<int> a,int n)
        {
            if(n==1)
            {
                vector<int> b(1);
                b[0]=1;
                return b;
            }
            vector<int> b=exp(a,(n+1)>>1);
            vector<int> f=ln(b,n);
            f[0]=(a[0]+1-f[0]+mod)%mod;
            for(int i=1;i<n;++i) f[i]=(a[i]-f[i]+mod)%mod;
            b=mul(b,f,n,n);
            b.resize(n);
            return b;
        }
    }
    inline void main()
    {
        auto fast=[&](int x,int k) -> int
        {
            int ret=1;
            while(k)
            {
                if(k&1) ret=ret*x%mod;
                x=x*x%mod;
                k>>=1;
            }
            return ret;
        };
        int n;
        cin>>n;
        vector<int> rd(n+1);
        for(int i=1;i<n;++i)
        {
            int x,y;
            cin>>x>>y;
            ++rd[x],++rd[y];
        }
        vector<int> c(n+1);
        ++rd[1];
        for(int i=1;i<=n;++i) ++c[rd[i]-1];
        vector<int> fac(n+1),inv(n+1);
        fac[0]=inv[0]=1;
        for(int i=1;i<=n;++i) fac[i]=fac[i-1]*i%mod;
        inv[n]=fast(fac[n],mod-2);
        for(int i=n-1;i>=1;--i) inv[i]=inv[i+1]*(i+1)%mod;
        auto C=[&](int n,int m) -> int 
        {
            if(n<m||m<0) return 0;
            return fac[n]*inv[m]%mod*inv[n-m]%mod;
        };
        vector<int> f(1,1);
        for(int i=n;i>=1;--i) if(c[i])
        {
            vector<int> g(c[i]+1);
            int now=1;
            for(int j=0;j<=c[i];++j)
                g[j]=now*C(c[i],j)%mod,now=now*i%mod;
            f=NTT::mul(f,g);
        }
        int ans=0;
        int len=min(n,(int)f.size());
        for(int i=0;i<len;++i)
        {
            if(i&1) ans-=fac[n-i]*f[i];
            else ans+=fac[n-i]*f[i];
            ans%=mod;
        }
        cout<<(ans+mod)%mod<<'\n';
    }
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    red::__init();
    int qwq=1; //cin>>qwq;
    while(qwq--) red::main();
    return 0;
}
/*
1 2 5 10

*/

ABC135E

题意:

给一个目标点\((x,y)\),从\((0,0)\)出发,每次可以移动到距离当前曼哈顿距离为\(k\)的地方,最少几次能到达\((x,y)\),输出路径。

\(-10^5\leq x,y\leq 10^5\)

\(1\leq k\leq 10^9\)

题解:

不妨设\(x,y\geq 0\),然后把输出路径带上符号

先考虑无解的情况,如果\(k\)是偶数而\(x+y\)是奇数则无解,其他情况都可以通过凑\(k\)到达。

先把一步可以到位的情况特判掉,因为只有一步的话没有操作空间。

否则可以通过这样到达目标点

那么最少的步数可以表示为最小的\(2\leq n\)满足\((n*k\geq x+y\&\&(n*k-x-y)\%2==0)\)

因为步数不会特别多,可以暴力求。

设\(t1+t2=b\),那么就可以得知\(b=\frac{n*k-x-y}{2}\)

然后就是要把\(b\)的步数先走完,再直接朝着目标点就走可以了。

如果\(b\geq k\)

那么选择最接近目标点的一个方向,直接后退\(k\)步。

如果\(b<k\)

还是选最接近目标点的一个方向后退\(b\)步,另一个方向朝着目标点前进\(k-b\)步。

如果\(b=0\),那就说明退完了,直接朝着目标点前进。

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define double long double
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define lowbit(i) ((i)&(-i))
#define mid ((l+r)>>1)
#define eps (1e-15)
    const int N=1e6+10,mod=1e9+7,inf=2e15;
    void __init(int n=2000) {}
    inline void main()
    {
        int k,x,y;
        cin>>k>>x>>y;
        int opx=x/abs(x),opy=y/abs(y);
        int n=2;
        x=abs(x),y=abs(y);
        int s=x+y;
        if(s==k)
        {
            cout<<"1\n"<<x*opx<<' '<<y*opy;
            return;  
        }
        if(k%2==0&&s%2==1)
        {
            cout<<"-1\n";
            return;
        }
        while(n*k<s||(n*k-s)%2) ++n;
        cout<<n<<'\n';
        int a=(n*k+s)/2,b=(n*k-s)/2;
        for(int tx=0,ty=0;n--;cout<<tx*opx<<' '<<ty*opy<<'\n')
        {
            if(b)
            {
                if(b>=k)
                {
                    if(x-tx<y-ty) tx-=k;
                    else ty-=k;
                    b-=k;
                }
                else
                {
                    if(x-tx<y-ty) tx-=b,ty+=k-b;
                    else ty-=b,tx+=k-b;
                    b=0;
                }
            }
            else
            {
                if(tx<x)
                {
                    if(x-tx>=k) tx+=k;
                    else ty+=k-x+tx,tx=x;
                }
                else ty+=k;
            }
        }
    }
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    red::__init();
    int qwq=1; //cin>>qwq;
    while(qwq--) red::main();
    return 0;
}
/*
1 2 5 10

*/

标签:return,int,inv,vector,limit,9.1,mod
来源: https://www.cnblogs.com/knife-rose/p/16648456.html