jzoj5894. 【NOIP2018模拟10.5】同余方程

Description

在这里插入图片描述

Input

在这里插入图片描述

Output

在这里插入图片描述

Sample Input

123 1234 234 2345 5

Sample Output

470244

Data Constraint

在这里插入图片描述

题解

这道题真的是一道传说中的想法超级简单而实现起来细节超级多超级繁琐的题。
调了我两天
废话不多说。
30%直接暴力
60%据说可以用trie做。然而我不会
100%
我们观察一下题目。
我们发现,我们设一个函数f(a,b)表示0 ~ a和0 ~ b这范围内的两两xor值为m的方案。
答案即为:f(r1,r2)f(l11,r2)f(r1,l21)+f(l11,l21)f(r1,r2)-f(l1-1,r2)-f(r1,l2-1)+f(l1-1,l2-1)
我们又发现,题目实际上可以用类似于数形dp的套路,把一个数分成“1001101……”的形式,然后处理。
那么对于两个上界a,b。我们如何统计0 ~ a与0 ~ b的值呢?
首先把a,b拆成二进制,然后我们就从高位往低位枚举;
我们找到当前位置为1的位置,把当前位置看做是0,那么左边就是全部与原来的a(b)相同的,右边则是不定的,怎么填数字都是可以的(比上界小)。
在这里插入图片描述
(红色为确定的,蓝色为当前点,要变成0,黄色为不定的)
然后,我们考虑把当前这两种情况给xor起来,就会发现:
在这里插入图片描述
那么,就会分成三种情况:红色为确定的,绿色为一半确定,一半不定,黄色是全部不确定的。
我们就看看如何记录答案。
对于一个新的C的值,我们要使得C确定时有多少方案,那么红色确定,绿色虽然不确定,但要符合C的值,所以也是确定的。
然而对于这个黄色,它要变成一个确定的,那么就有2p2^p(p为黄色段的长度)
我们再回到题目,发现A xor B|m,那么我们当前的这个C就是在op2p+qop*2^{p+q}(q为绿色段的长度,op为红色段的值。)到op2p+q+2p+q1op*2^{p+q}+2^{p+q}-1
也就是:在这里插入图片描述
我们就要在上面的两个式子中找到是m倍数的个数再乘上2p2^p即可。
关于找r~l之间是m倍数的个数:r/m-(l-1)/m
很多细节,自己慢慢玩:

var
        i,j,k,l,n:longint;
        l1,r1,l2,r2,m,answer:int64;
        mi:array[0..63] of int64;
        mo:int64=998244353;
function f(a,b:int64):int64;
var
        i,j,k,upa,upb:longint;
        ta,tb,ja,jb:array[0..100] of longint;
        op,sa,sb,an,l,r,pp:int64;
begin
        fillchar(ja,sizeof(ja),0);
        fillchar(jb,sizeof(jb),0);
        op:=a;upa:=0;upb:=0;
        while op>0 do
        begin
                op:=op div 2;
                inc(upa);
        end;
        op:=a;
        j:=1;
        for i:=upa downto 1 do
        begin
                ja[i]:=op mod 2;
                op:=op div 2;
        end;
        op:=b;
        while op>0 do
        begin
                op:=op div 2;
                inc(upb);
        end;
        op:=b;
        j:=1;
        for i:=upb downto 1 do
        begin
                jb[i]:=op mod 2;
                op:=op div 2;
        end;
        f:=0;
        sa:=0;
        for i:=1 to upa do
        begin
                if ja[i]=1 then
                begin
                ta[i]:=0;
                sb:=0;
                for j:=1 to upb do
                begin
                        if jb[j]=1 then
                        begin
                        tb[j]:=0;
                        if (upa-i)>(upb-j) then
                        begin
                                op:=sa xor (sb div mi[(upa-i)-(upb-j)]);
                                an:=mi[upb-j] mod mo;
                                op:=op mod m;
                                l:=op*mi[upa-i];
                                r:=op*mi[upa-i]+mi[upa-i]-1;
                                pp:=(r div m-(l-1) div m) mod mo;
                                if l=0 then inc(pp);
                                f:=(f+(pp*an) mod mo) mod mo;
                        end
                        else
                        begin
                                op:=sb xor (sa div mi[(upb-j)-(upa-i)]);
                                an:=mi[upa-i] mod mo;
                                op:=op mod m;
                                l:=op*mi[upb-j];
                                r:=op*mi[upb-j]+mi[upb-j]-1;
                                pp:=(r div m-(l-1) div m) mod mo;
                                if l=0 then inc(pp);
                                f:=(f+(pp*an) mod mo) mod mo;
                        end;
                        end;
                        tb[j]:=jb[j];
                        sb:=(sb+tb[j])*2;
                end;
                fillchar(tb,sizeof(tb),0);
                end;
                ta[i]:=ja[i];
                sa:=(sa+ta[i])*2;
        end;
        fillchar(tb,sizeof(tb),0);
        ta:=ja;
        sa:=a;
        sb:=0;
        if upa>0 then
        for j:=1 to upb do
        begin
                if jb[j]=1 then
                begin
                tb[j]:=0;
                if (upa-i)>(upb-j) then
                begin
                        op:=sa xor (sb div mi[(upa-i)-(upb-j)]);
                        an:=mi[upb-j] mod mo;
                        op:=op mod m;
                        l:=op*mi[upa-i];
                        r:=op*mi[upa-i]+mi[upa-i]-1;
                        pp:=(r div m-(l-1) div m) mod mo;
                        if l=0 then inc(pp);
                        f:=(f+(pp*an) mod mo) mod mo;
                end
                else
                begin
                        op:=sb xor (sa div mi[(upb-j)-(upa-i)]);
                        an:=mi[upa-i] mod mo;
                        op:=op mod m;
                        l:=op*mi[upb-j];
                        r:=op*mi[upb-j]+mi[upb-j]-1;
                        pp:=(r div m-(l-1) div m) mod mo;
                        if l=0 then inc(pp);
                        f:=(f+(pp*an) mod mo) mod mo;
                end;
                end;
                tb[j]:=jb[j];
                sb:=(sb+tb[j])*2;
        end;
        tb:=jb;
        fillchar(ta,sizeof(ta),0);
        sb:=b;
        sa:=0;
        if upb>0 then
        for i:=1 to upa do
        begin
                if ja[i]=1 then
                begin
                ta[i]:=0;
                if (upa-i)>(upb-j) then
                begin
                        op:=sa xor (sb div mi[(upa-i)-(upb-j)]);
                        an:=mi[upb-j] mod mo;
                        op:=op mod m;
                        l:=op*mi[upa-i];
                        r:=op*mi[upa-i]+mi[upa-i]-1;
                        pp:=(r div m-(l-1) div m) mod mo;
                        if l=0 then inc(pp);
                        f:=(f+(pp*an) mod mo) mod mo;
                end
                else
                begin
                        op:=sb xor (sa div mi[(upb-j)-(upa-i)]);
                        an:=mi[upa-i] mod mo;
                        op:=op mod m;
                        l:=op*mi[upb-j];
                        r:=op*mi[upb-j]+mi[upb-j]-1;
                        pp:=(r div m-(l-1) div m) mod mo;
                        if l=0 then inc(pp);
                        f:=(f+(pp*an) mod mo) mod mo;
                end;
                end;
                ta[i]:=ja[i];
                sa:=(sa+ta[i])*2;
        end;
        ta:=ja;
        tb:=jb;
        sa:=a;sb:=b;
        if (upa>0) and (upb>0) then
        begin
        if (upa-i)>(upb-j) then
        begin
                op:=sa xor (sb div mi[(upa-i)-(upb-j)]);
                an:=mi[upb-j] mod mo;
                op:=op mod m;
                l:=op*mi[upa-i];
                r:=op*mi[upa-i]+mi[upa-i]-1;
                pp:=(r div m-(l-1) div m) mod mo;
                if l=0 then inc(pp);
                f:=(f+(pp*an) mod mo) mod mo;
        end
        else
        begin
                op:=sb xor (sa div mi[(upb-j)-(upa-i)]);
                an:=mi[upa-i] mod mo;
                op:=op mod m;
                l:=op*mi[upb-j];
                r:=op*mi[upb-j]+mi[upb-j]-1;
                pp:=(r div m-(l-1) div m) mod mo;
                if l=0 then inc(pp);
                f:=(f+(pp*an) mod mo) mod mo;
        end;
        end;
        if (a=0) and (b>0) then
        begin
        sb:=0;
        for j:=1 to upb do
        begin
                if jb[j]=1 then
                begin
                tb[j]:=0;
                op:=sb xor (sa div mi[(upb-j)]);
                an:=1;
                op:=op mod m;
                l:=op*mi[upb-j];
                r:=op*mi[upb-j]+mi[upb-j]-1;
                pp:=(r div m-(l-1) div m) mod mo;
                if l=0 then inc(pp);
                f:=(f+(pp*an) mod mo) mod mo;
                end;
                tb[j]:=jb[j];
                sb:=(sb+tb[j])*2;
        end;
        if (b xor 0) mod m=0 then inc(f);
        end
        else
        if (a>0) and (b=0) then
        begin
        sa:=0;
        for i:=1 to upa do
        begin
                if ja[i]=1 then
                begin
                ta[i]:=0;
                op:=sa xor (sb div mi[(upa-i)]);
                an:=1;
                op:=op mod m;
                l:=op*mi[upa-i];
                r:=op*mi[upa-i]+mi[upa-i]-1;
                pp:=(r div m-(l-1) div m) mod mo;
                if l=0 then inc(pp);
                f:=(f+(pp*an) mod mo) mod mo;
                end;
                ta[i]:=ja[i];
                sa:=(sa+ta[i])*2;
        end;
        if (a xor 0) mod m=0 then inc(f);
        end
        else
        if (a=0) and (b=0) then
        begin
                f:=1;
        end;
end;
begin
        assign(input,'mod.in');reset(input);
        assign(output,'mod.out');rewrite(output);
        mi[0]:=1;
        for i:=1 to 62 do
        begin
                mi[i]:=mi[i-1]*2;
        end;
        readln(l1,r1,l2,r2,m);
        writeln((f(r1,r2)-f(l1-1,r2)-f(r1,l2-1)+f(l1-1,l2-1)+mo) mod mo);
end.


我活在这夜里。无论周围多么黑暗,我都要努力发光!我相信着,终有一天,我会在这深邃的夜里,造就一道最美的彩虹。
原文地址:https://www.cnblogs.com/RainbowCrown/p/11148387.html