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