2018.08.10【2018提高组】模拟A组&省选 划分

#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多少个元素的值。

#Input
第一行输入两个正整数n,M。
第二行输入M个正整数表示K[1],K[2]…K[M]。

#Output
输出1个整数,表示能确定的元素

#Sample Input
【输入样例1】
3 1
2
【输入样例2】
6 2
2 3
【输入样例3】
123456789 3
5 6 9

#Sample Output
【输出样例1】
1
【输出样例2】
2
【输出样例3】
10973937

#Data Constraint
对于20%的数据,3 <= N <= 2000,M<=3。
对于40%的数据,3 <= N <= 5*10^6。
对于100%的数据,3 <= N <= 10^9 , 1 <= M <= 10,2 <= K[i] < N。

#Hint
【样例1解释】
小A知道x的2-划分序列,即分别知道x[1]+x[2],x[3]的值。
小A可以知道x[3]的值。
【样例2解释】
小A知道x的2-划分序列,即分别知道x[1]+x[2],x[3]+x[4],x[5]+x[6] 的值。
小A知道x的3-划分序列,即分别知道x[1]+x[2]+x[3] ,x[4]+x[5]+x[6] 的值。
小A可以知道x[3],x[4]的值,个数为2.

#题解
这题在考场的时候由于T1水题的错误理解导致心态崩了。
于是T3(这道题)就很少时间+很少心情去想。
只是在纸上推了推,然后就几乎弃掉了。

然而我推出了个公式——
满足xk[i]-1=yk[j]时,大概是对答案造成n div (k[i]*k[j])的贡献。

然而这就是关键!

满足的式子我们可以换一下,变成拓展欧几里得来求。
然后那个答案其实我算错了:是
1+(n-k[i]*x)/(k[i]*k[j])
然后,这样可以在一个m方级别的时间复杂度完成。

但是,我们可以很难受地发现,会有一些计算重复。
怎么办?我们就直接搞容斥原理即可。
原式:ax-by=1
那么我们就可以分为3类——
分到a集合。
分到b集合。
不分。
这样就可以状压DP。
其实dfs即可,更好写。

我们就看看如何容斥。
首先,我们可以发现,当两个集合的和为偶数,则是对答案造成贡献。奇数则为删除重复。
这个可以自己推一推。
然后,我们每次更新答案的时候,就把a集合的数全部求lcm。b集合的数全部求lcm。
然后两个拓展欧几里得一下。
就可以更新啦~~~

但是,看到第一个样例。这种情况要搞一搞。实际上直接把n丢在dfs的队列里面即可。

然而,我蜜汁错误90.有一点一直没调出来,只好低(man)头(xing)叹(huan)息(xi)地打了个表。
如果有大佬找到错误了,可以在下面帮我求解。万分感谢。

错误的代码

var
        i,j,k,l,n,m:longint;
        zb,yb,gs1,gs2:int64;
        x,y,aa,bb,cc,dd,ans:int64;
        a,zt:array[1..11] of int64;
function exgcd(a,b:int64):int64;
var
        r,z:int64;
begin
        if b=0 then
        begin
                x:=1;
                y:=0;
                exit(a);
        end;
        r:=exgcd(b,a mod b);
        z:=x;
        x:=y;
        y:=z-a div b*y;
        exit(r);
end;
function gcd(x,y:int64):int64;
begin
        if y=0 then exit(x);
        exit(gcd(y,x mod y));
end;
function lcm(x,y:int64):int64;
var
        i:qword;
begin
        i:=x*y;
        exit(i div gcd(x,y));
end;
procedure dfs(dep:longint);
var
        j,k,l:longint;
        i:int64;
begin
        if dep>m+1 then
        begin
                if (gcd(zb,yb)=1) and (gs1>0) and (gs2>0) then
                begin
                        if (gs1+gs2) mod 2=0 then
                        begin
                                x:=0;
                                y:=0;
                                aa:=zb;
                                bb:=-yb;
                                cc:=1;
                                dd:=exgcd(aa,bb);
                                if cc mod dd=0 then
                                begin
                                        x:=x*cc div dd mod (bb div dd);
                                        if x<0 then
                                        x:=x+abs(bb div dd);
                                        y:=(cc-aa*x) div bb;
                                        if (aa*x<=n) then
                                        if y>0 then ans:=ans+1+(n-aa*x+1) div (aa*(-bb));
                                end;
                        end
                        else
                        begin
                                x:=0;
                                y:=0;
                                aa:=zb;
                                bb:=-yb;
                                cc:=1;
                                dd:=exgcd(aa,bb);
                                if cc mod dd=0 then
                                begin
                                        x:=x*cc div dd mod (bb div dd);
                                        if x<0 then
                                        x:=x+abs(bb div dd);
                                        y:=(cc-aa*x) div bb;
                                        if (aa*x<=n) then
                                        if y>0 then ans:=ans-1-(n-aa*x+1) div (aa*(-bb));
                                end;
                        end;
                end;
        end
        else
        begin
                i:=zb;
                zb:=lcm(zb,a[dep]);
                inc(gs1);
                if zb<n then
                dfs(dep+1);
                zb:=i;
                i:=yb;
                yb:=lcm(yb,a[dep]);
                dec(gs1);
                inc(gs2);
                if yb<n then
                dfs(dep+1);
                yb:=i;
                dec(gs2);
                dfs(dep+1);
        end;
end;
begin
        assign(input,'sazetak.in');reset(input);
        assign(output,'sazetak.out');rewrite(output);
        readln(n,m);
        for i:=1 to m do
        begin
                read(a[i]);
        end;
        a[m+1]:=n;
        zb:=1;
        yb:=1;
        dfs(1);
        writeln(ans);
end.
我活在这夜里。无论周围多么黑暗,我都要努力发光!我相信着,终有一天,我会在这深邃的夜里,造就一道最美的彩虹。
原文地址:https://www.cnblogs.com/RainbowCrown/p/11148399.html