BZOJ3859: Periodic Binary String

42 篇文章 0 订阅
32 篇文章 0 订阅

我们可以旋转串T,使得l~r等价于0~r-l
根据(r-l)%k可以将T分成T1,T2两部分,问题变成满足 0<=a<2|T1|0<=b<2|T2| pa+qbx(Mod p) 的解数
也即 0<=a<A,0<=b<B
A=k1p+ka,B=k2p+kb ,当 ka kb 等于0的时候比较好讨论不在此处赘述,下面讨论 ka,kb0 的情况
0<=a<k1p 时,对于任意一个b,都有k1个a与之对应
k1p<=a<k1p+ka,0<=b<k2p 时,对于任意一个a,都有k2个b与之对应

所以我们不妨设 0<=a<ka,0<=b<kb (ka,kb<p)

画一下柿子
a+qpbxp(Mod p)
kb[l,r)(Mod p)
然后有个结论: ϵ(x[l,r)(Mod p)=[xlp][xrp](l<r)
于是 ans=kb1b=0[kblp]kb1b=0[kbrp]
然后就是一个类欧几里得了

然后..就没了…什么你问我为什么写的这么长??当然是因为…zzdsy不滋滋int128啊….要手写高精啊

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

ll mul(ll a,ll b,ll mod)
{
    if(a>=mod) a%=mod;
    if(b>=mod) b%=mod;
    ll re=0;
    while(b)
    {
        if(b&1) re=(re+a)%mod;
        a=(a+a)%mod;
        b>>=1;
    }
    return re;
}
ll pw(ll x,ll k,ll mod)
{
    if(x>=mod) x%=mod;
    ll re=1ll;
    for(;k;k>>=1,x=mul(x,x,mod)) if(k&1ll)
        re=mul(re,x,mod);
    return re;
}
ll inv(ll x,ll mod) { return pw(x,mod-2,mod); }
ll sum(ll n,ll mod) { return mul(mul(n,n+1ll,mod),inv(2ll,mod),mod); }

const ll bit = 1e18;
int use[40],tp;

struct bignum
{
    ll a,b;
    void build(bignum x)
    {
        while(tp) use[tp--]=0;
        for(int i=1;i<=18&&x.b;i++)
            use[i]=x.b%10,x.b/=10ll;
        for(int i=19;i<=36&&x.a;i++)
            use[i]=x.a%10,x.a/=10ll;
        tp=36; while(!use[tp]) tp--;
    }
    void div(bignum &x)
    {
        ll cc=x.a&1; x.a>>=1;
        cc*=bit; cc+=x.b; x.b=cc>>1;
    }
    friend inline bool operator ==(const bignum &x,const bignum &y){return x.a==y.a&&x.b==y.b;}
    friend inline bool operator <(const bignum &x,const bignum &y){return x.a<y.a||(x.a==y.a&&x.b<y.b);}
    friend inline bool operator >(const bignum &x,const bignum &y){return x.a>y.a||(x.a==y.a&&x.b>y.b);}
    friend inline bignum operator +(const bignum &x,const bignum &y)
    {
        ll cc=x.b+y.b;
        return (bignum){x.a+y.a+cc/bit,cc%bit};
    }
    friend inline bignum operator -(const bignum &x,const bignum &y)
    {
        ll cc=x.b-y.b;
        return cc<0?(bignum){x.a-y.a-1,cc+bit}:(bignum){x.a-y.a,cc};
    }
};
bignum zero,one,two,ten;
bignum bigmul(bignum x,bignum y)
{
    bignum re=zero,temp;
    while(!(y==zero))
    {
        if(y.b&1ll) re=re+x;
        x=x+x;
        temp.div(y);
    }
    return re;
}
bignum bigmulmod(bignum x,bignum y,const bignum &mod)
{
    bignum re=zero,temp;
    while(!(y==zero))
    {
        if(y.b&1ll)
        {
            re=re+x;
            if(re>mod||re==mod) re=re-mod;
        }
        x=x+x; if(x>mod||x==mod) x=x-mod;
        temp.div(y);
    }
    return re;
}
inline bignum operator /(const bignum &x,const bignum &y)
{
    bignum cc; cc.build(x);
    bignum re=zero,now=zero;
    for(int i=tp;i>=1;i--)
    {
        now=bigmul(now,ten); now=now+(bignum){0ll,use[i]};
        re=bigmul(re,ten);
        while(now>y||now==y) now=now-y,re=re+one;
    }
    return re;
}
bignum bigpow(bignum x,ll k,const bignum &mod)
{
    bignum re=one;
    for(;k;k>>=1,x=bigmulmod(x,x,mod)) if(k&1ll)
        re=bigmulmod(re,x,mod);
    return re;
}

bignum Mod;
const ll mod = 1e9+7;

ll p,x,l,r,k;
ll c1,c2,T1,T2;
ll cal(ll a,ll b,ll c,ll n)
{
    if(n<0) return 0;
    ll re=0;
    if(a<0)
    {
        ll tmp=(c-1-a)/c; re-=tmp%mod*sum(n,mod)%mod;
        a+=tmp*c;
    }
    if(a>=c)
    {
        ll tmp=a/c; re+=tmp%mod*sum(n,mod)%mod;
        a-=tmp*c;
    }
    if(b<0)
    {
        ll tmp=(c-1-b)/c; re-=tmp%mod*((n+1ll)%mod)%mod;
        b+=tmp*c;
    }
    if(b>=c)
    {
        ll tmp=b/c; re+=tmp%mod*((n+1ll)%mod)%mod;
        b-=tmp*c;
    }
    if(!a||!n) return re;
    bignum t1=(bignum){0ll,a},t2=(bignum){0ll,n},t3=(bignum){0ll,b};
    t1=bigmul(t1,t2); t1=t1+t3; t1=t1/(bignum){0ll,c};
    ll m=t1.b;

    re+=n%mod*(m%mod)%mod;
    re-=cal(c,c-b-1,a,m-1);
    re=(re%mod+mod)%mod;
    return re;
}
ll solve0()
{
    ll ans=0;
    if(!c1) ans=!x?pw(2ll,T1,mod):0ll;
    else
    {
        x=mul(x,inv(c1,p),p);
        bignum Qa=bigpow(two,T1,Mod); Qa=Qa/(bignum){0ll,p}; ll qa=Qa.b;
        ll ka=pw(2ll,T1,p);
        ans=qa; if(ka>=x) ans++;
    }
    ans=(ans%mod+mod)%mod;
    ans=ans*pw(2ll,T2,mod)%mod;
    return ans;
}
ll solve()
{
    if(!c1) swap(c1,c2),swap(T1,T2);
    if(!c2) return solve0();

    ll ans=0;

    bignum Qa=bigpow(two,T1,Mod); Qa=Qa/(bignum){0ll,p}; ll qa=Qa.b;
    ll ka=pw(2ll,T1,p);
    ans=qa%mod*pw(2ll,T2,mod)%mod;

    bignum Qb=bigpow(two,T2,Mod); Qb=Qb/(bignum){0ll,p}; ll qb=Qb.b;
    ll kb=pw(2ll,T2,p);
    ans=(ans+(qb%mod)*(ka%mod)%mod)%mod;

    if(ka&&kb)
    {
        ll cc=inv(c1,p); c2=mul(c2,cc,p); x=mul(x,cc,p);
        ans=(ans+cal(-c2,x,p,kb-1))%mod;
        ans=(ans-cal(-c2,x-ka,p,kb-1)+mod)%mod;
    }
    return ans;
}

int main()
{
    zero.a=zero.b=0ll;
    one.a=0,one.b=1ll;
    two.a=0,two.b=2ll;
    ten.a=0,ten.b=10ll;

    int tcase=0;
    while(scanf("%lld%lld%lld%lld%lld",&p,&x,&l,&r,&k)!=EOF&&p)
    {
        Mod=bigmul((bignum){0ll,p},(bignum){0ll,mod});

        r=r-l+1;
        if(r<=k)
        {
            T1=r,T2=k-r;
            c1=1,c2=0;
        }
        else if(r%k==0)
        {
            T1=k,T2=0;
            ll t1=pw(2ll,r,p); t1=(t1-1+p)%p;
            ll t2=pw(2ll,k,p); t2=(t2-1+p)%p;
            if(t2) t1=mul(t1,inv(t2,p),p);
            else t1=r/k;
            c1=t1,c2=0;
        }
        else
        {
            T1=r%k,T2=k-T1;
            ll t1=pw(2ll,(r/k+1)*k,p); t1=(t1-1+p)%p;
            ll t2=pw(2ll,k,p); t2=(t2-1+p)%p;
            if(t2) c1=mul(t1,inv(t2,p),p);
            else c1=r/k+1;

            t1=pw(2ll,r/k*k,p); t1=(t1-1+p)%p; ll cc=pw(2ll,T1,p); t1=mul(t1,cc,p);
            t2=pw(2ll,k,p); t2=(t2-1+p)%p;
            if(t2) c2=mul(t1,inv(t2,p),p);
            else c2=mul(cc,r/k,p);
        }
        printf("Case #%d: %lld\n",++tcase,solve());
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值