Description
有一个未知的序列x,长度为n。它的K-划分序列y指的是每连续K个数的和得到划分序列,y[1]=x[1]+x[2]+….+x[K],y[2]=x[K+1]+x[K+2]+….+x[K+K]….。若n不被K整除,则y[n/K+1]可以由少于K个数加起来。比如n=13,K=5,则y[1]=x[1]+…+x[5],y[2]=x[6]+….+x[10],y[3]=x[11]+x[12]+x[13]。若小A只确定x的K[1]划分序列以及K[2]划分序列….K[M]划分序列的值情况下,问她可以确定x多少个元素的值。
对于20%的数据,3 <= N <= 2000,M<=3。
对于40%的数据,3 <= N <= 5*10^6。
对于100%的数据,3 <= N <= 10^9 , 1 <= M <= 10,2 <= K[i] < N。
Solution
我好菜啊
一个位置x能够确定当且仅当我们知道x这一位置的前缀和与x-1这一位置的前缀和
那么就是
x≡1(moda[i])x≡0(moda[j])(63)(64)
(63)
x
≡
1
(
mod
a
[
i
]
)
(64)
x
≡
0
(
mod
a
[
j
]
)
我们对所有的a分成三组,分别是余1、余0、不选。注意到同余的可以合并,模数变为lcm,因此最后剩下两个方程直接exgcd出解
这样算会算重,因此要容斥
Code
#include <stdio.h>
#include <string.h>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
typedef long long LL;
const int N=1025;
LL a[N],ans,n,m;
LL gcd(LL x,LL y) {
return !y?x:gcd(y,x%y);
}
void exgcd(LL a,LL b,LL &x,LL &y) {
if (!b) {
x=1; y=0; return ;
}
exgcd(b,a%b,x,y);
LL tmp=x; x=y; y=tmp-(a/b)*y;
}
void dfs(int dep,LL lcm1,LL lcm2,int s1,int s2,LL r) {
if (lcm1>n||lcm2>n) return ;
if (dep==m+1) {
if (!(s1*s2)) return ;
if (gcd(lcm1,lcm2)!=1) return ;
LL x,y; exgcd(lcm1,lcm2,x,y);
x%=lcm2;
while (x<=0) x+=lcm2;
ans+=r*n/lcm1/lcm2+r*(x<=(n/lcm1%lcm2));
return ;
}
dfs(dep+1,lcm1,lcm2,s1,s2,r);
dfs(dep+1,lcm1/gcd(lcm1,a[dep])*a[dep],lcm2,s1|(1<<dep-1),s2,-r);
dfs(dep+1,lcm1,lcm2/gcd(lcm2,a[dep])*a[dep],s1,s2|(1<<dep-1),-r);
}
int main(void) {
// freopen("sazetak.in","r",stdin);
// freopen("sazetak.out","w",stdout);
scanf("%lld%lld",&n,&m);
rep(i,1,m) scanf("%lld",&a[i]); a[++m]=n;
dfs(1,1,1,0,0,1);
printf("%lld\n", ans);
return 0;
}