[数学杂题] LibreOJ#532. 「LibreOJ β Round #5」随机数列

Xi 的取值一共就 C 种,所以数列一定存在环,数列长度没影响,对于每个数字,我们都能方便算出他在 L,R 出现了几次。
现在我们的目标就是算出:

x1=1Cx2=1Ccnt[x1]cnt[x2]x1x2+x2x1

f(x1,x2)=x1x2+x2x1 考虑一下 f 的范围,就是个对钩函数,且x只能取整数,所以最大值为只是 c+1 ,说明有很多对x1,x2f 都是相同的。
=x=1Ccnt1[x]cnt2[x]f(x,x)+x1=1Ck=2(C+1)/x1(cnt[x1]([f(x1,x2)=k]cnt[x2])+cnt[x2]([f(x1,x2)=k]cnt[x1]))

[f(x1,x2)=k]cnt[x2] 这样的东西可以预处理前缀和+解方程O(1)求。
然后因为 (C+1)/x1 ,所以直接枚举一个x和k就好了,由于调和级数所以 O(ClogC)

代码能力还不够….打的时候很多小问题…

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=1000015, MOD=1e9+7;
int n;
LL _A,_B,_C,a[maxn],L1,R1,L2,R2,sum1[maxn],sum2[maxn],ans;
int pos[maxn],pos_b;
bool in_c[maxn];
inline LL Calc(LL L,LL R,int val){
    if(!pos[val]) return 0;
    if(!in_c[val]) return L<=pos[val];
    LL res=0;
    if(R>pos_b) res+=(R-pos_b)/(n-pos_b)+(pos[val]-pos_b<=(R-pos_b)%(n-pos_b));
    if(L-1>pos_b) res-=(L-1-pos_b)/(n-pos_b)+(pos[val]-pos_b<=(L-1-pos_b)%(n-pos_b));
    return res%MOD;
}
void Pre(){
    for(n=1;;n++){
        a[n]=(a[n-1]*_A+_B)%_C+1;
        if(pos[a[n]]) break; pos[a[n]]=n;
    }
    pos_b=pos[a[n--]]-1;
    for(int i=pos_b+1;i<=n;i++) in_c[a[i]]=true;
    for(int i=1;i<=_C;i++) sum1[i]=(Calc(L1,R1,i)+sum1[i-1])%MOD;
    for(int i=1;i<=_C;i++) sum2[i]=(Calc(L2,R2,i)+sum2[i-1])%MOD;
}
inline int f(double x,double y){ return ceil(x/y+y/x); }
inline int get(double x,double k){ return min(_C,(LL)floor(x*(k+sqrt(k*k-4))/2));}
int main(){
    freopen("loj532.in","r",stdin);
    freopen("loj532.out","w",stdout);
    scanf("%lld%lld%lld%lld%lld%lld%lld%lld",&_A,&_B,&_C,&a[0],&L1,&R1,&L2,&R2);
    Pre();
    for(int i=1;i<=_C;i++) (ans+=(sum1[i]-sum1[i-1])%MOD*((sum2[i]-sum2[i-1])%MOD)%MOD*2%MOD)%=MOD;
    for(int x=1;x<=_C;x++){
        for(int k=3,lst=get(x,2);k<=_C+1;k++){
            int t=get(x,k);
            (ans+=((sum1[t]-sum1[lst])*(sum2[x]-sum2[x-1])%MOD+(sum2[t]-sum2[lst])*(sum1[x]-sum1[x-1])%MOD)%MOD*k%MOD)%=MOD;
            if(t==_C) break; lst=t;
        }
    }
    printf("%d\n",(ans+MOD)%MOD);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值