[dfs][exgcd][容斥原理] Jzoj P5796 划分
Posted comfortable
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[dfs][exgcd][容斥原理] Jzoj P5796 划分相关的知识,希望对你有一定的参考价值。
题解
- 首先,如果x[p]能算出来,对于一组(i,j),必存在P%k[i]=0,P%k[j]=1
- 也就是a1*k[i]-a2*k[j]=1,这个显然可以用扩展欧几里得来求解,且要满足gcd(k[i],k[j])=1
- 然后这样的话,会出现重复计算,考虑容斥
- 容斥系数就是子数的奇偶性
- 观察一下式子:
P mod k[i1]=0,P mod k[i2]=0,P mod k[i3]=0, …… - P mod k[j1]=1,P mod k[j2]=1,P mod k[j3]=1, ……
- 其实等价于P mod lcm(k[i1],k[i2]...)=0 P mod lcm(k[j1],k[j2...)==1
- 这个可以用扩展欧几里得来解,然后对于一组解的可求出P的方案数为ki∗x∈[1,n]的个数
- 还要特殊判断n的位置
代码
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 using namespace std; 5 int i,n,m,k[12]; 6 long long d,x,y,ans; 7 void exgcd(long long a,long long b,long long &d,long long &x,long long &y) 8 { 9 if (!b) d=a,x=1,y=0; 10 else exgcd(b,a%b,d,y,x),y=y-x*(a/b); 11 } 12 long long gcd(long long x,long long y) { return y?gcd(y,x%y):x; } 13 long long lcm(long long x,long long y) { return x*y/gcd(x,y); } 14 void dfs(int t,long long tot1,long long tot2,long long x1,long long x2,long long w) 15 { 16 if (x1>n||x2>n) return; 17 if (t>m) 18 { 19 if (tot1==0||tot2==0) return; 20 exgcd(x1,x2,d,x,y); 21 if (d<0) x=-x,y=-y,d=-d; 22 if (d>1) return; 23 x=(x%x2+x2)%x2; 24 ans+=w*((1LL*n/x1-x)/x2+(x1*x<=n)); 25 return; 26 } 27 dfs(t+1,tot1,tot2,x1,x2,w); 28 dfs(t+1,tot1+1,tot2,lcm(x1,k[t]),x2,-w); 29 dfs(t+1,tot1,tot2+1,x1,lcm(x2,k[t]),-w); 30 } 31 int main() 32 { 33 freopen("sazetak.in","r",stdin); 34 freopen("sazetak.out","w",stdout); 35 scanf("%d%d",&n,&m); 36 for (int i=1;i<=m;i++) scanf("%d",&k[i]); 37 k[++m]=n; 38 dfs(1,0,0,1,1,1); 39 printf("%lld",ans); 40 return 0; 41 }
以上是关于[dfs][exgcd][容斥原理] Jzoj P5796 划分的主要内容,如果未能解决你的问题,请参考以下文章