ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

9.1

2022-09-02 08:00:08  阅读:137  来源: 互联网

标签:return int inv vector limit 9.1 mod


小\(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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有