zoukankan      html  css  js  c++  java
  • 【牛客提高训练营5A】同余方程

    题目

    吉老师的题做不动啊

    首先([l_1,r_1],[l_2,r_2])并不是非常好做,我们考虑将其拆成前缀信息

    (solve(n,m)=sum_{i=0}^nsum_{j=0}^m[m|(iigoplus j)])

    于是我们的答案就变成了(solve(r_1,r_2)-solve(l_1-1,r_2)-solve(r_1,l_2-1)+solve(l_1-1,l_2-1))

    考虑(solve(r_1,r_2))怎么求

    一个非常特殊的情况是(r_1=2^n-1,r_2=2^m-1),不妨假设(n<m)([0,2^n))([0,2^m))各选择一个数异或起来,能取遍([0,2^m)),且每一个数出现的次数都是(2^n)

    正确性显然

    考虑推广到更一般的情况,我们把([0,r_1))拆分一下,拆分成(log)([v,v+2^k))的区间,比如说对于(101010),可以拆成([0,2^5),[2^5,2^5+2^3),[2^5+2^3,2^5+2^3+2^1))

    这样的拆分有一个特点,如果有(v eq 0),那么一定会存在(v>2^k),这个性质接下来非常重要

    ([0,r_1),[0,r_2))各拆成(log)段区间后,我们暴力从两边各选一段区间出来,假设为([x,x+2^a))([y,y+2^b)),还是不妨假设(a<b)

    于是在忽略(x,y)的情况下两个区间变成了([0,2^a),[0,2^b)),于是各选一个异或起来能取遍([0,2^b))且每个值能被异或出来(2^a)

    现在考虑把(x,y)引入,不难发现因为(x>2^a),所以从([0,2^a))拿出一个数,加上(x)和异或(x)是等价的;(y)那边同理

    于是([0,2^b))中的每一个数拿出来和(xigoplus y)异或一下,就是真实的从([x,x+2^a))([y,y+2^b))各拿一个数出来异或的结果。

    所以现在只需要求出([0,2^b))内有多少个满足异或(xigoplus y)( m mod m=0),这样的数的个数乘上(2^a)就是答案了

    做到这里就不会了,接下来都是祖特教我的。

    我们不难发现(xigoplus y)如果不是(0),则必然大于(2^b),于是(xigoplus y)([0,2^b))内的数异或,必然不会改变必(2^b)更高的二进制位。

    所以想要使得异或出来的数是(m)的倍数,只需要让(xigoplus y)小于(2^b)的位数从全(0)取到全(1),从中选出(m)的倍数即可。

    代码

    #include<bits/stdc++.h>
    #define re register
    #define LL long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    inline int read() {
    	char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    const int mod=998244353;
    inline int dqm(int x) {return x<0?x+mod:x;}
    inline int qm(int x) {return x>=mod?x-mod:x;}
    LL l1,l2,r1,r2;int m,top[2];
    struct Seg{LL v,k;}a[2][65];
    inline LL getid(LL a,LL b) {return a%b==0?a/b:a/b+1;}
    inline LL solve(LL n,LL k)
    {
        LL t=0,tot=0;
        for(re LL i=63;i>=0;i--)
        {
            t|=(1ll<<i);
            if(!(n&(1LL<<i))) continue;
            LL l=k&t,r=l+(1ll<<i)-1;
            LL L=getid(l,m),R=r/m;
            tot=qm(tot+(R-L+1)%mod);
        }
        return tot;
    }
    inline int calc(LL n,LL m) {
    	++n,++m;int ans=0;
    	top[0]=top[1]=0;
    	LL now=0;
    	for(re LL i=63;i>=0;--i)
    	if(n>>i&1ll) {
    		a[0][++top[0]].v=now,a[0][top[0]].k=i;
    		now|=(1ll<<i);
    	}  
    	now=0;
    	for(re LL i=63;i>=0;--i) 
    	if(m>>i&1ll) {
    		a[1][++top[1]].v=now,a[1][top[1]].k=i;
    		now|=(1ll<<i);
    	}
    	for(re int i=1;i<=top[0];++i)
    		for(re int j=1;j<=top[1];++j) {
    			now=a[0][i].v^a[1][j].v;
    			LL mx=max(a[0][i].k,a[1][j].k),mn=min(a[0][i].k,a[1][j].k);
    			mn=(1ll<<mn);mn%=mod;
    			ans=qm(ans+1ll*solve(1ll<<mx,now)%mod*mn%mod);
    		}
    	return ans;
    }
    int main() {
    	scanf("%lld%lld%lld%lld%d",&l1,&r1,&l2,&r2,&m);
    	printf("%d
    ",dqm(qm(calc(r1,r2)+calc(l1-1,l2-1))-qm(calc(l1-1,r2)+calc(r1,l2-1))));
    	return 0;
    }
    
  • 相关阅读:
    artDialog基本使用
    SQL数据类型(SQL Server六个类型使用)
    常用SQL语句大全(SQL Server)
    从PRISM开始学WPF(八)导航Navigation-更新至Prism7.1
    从PRISM开始学WPF(番外)共享上下文 RegionContext-更新至Prism7.1
    从PRISM开始学WPF(七)MVVM(三)事件聚合器EventAggregator-更新至Prism7.1
    从PRISM开始学WPF(六)MVVM(二)Command-更新至Prism7.1
    从PRISM开始学WPF(四)Prism-Module-更新至Prism7.1
    从PRISM开始学WPF(二)认识Prism-更新至Prism7.1
    从PRISM开始学WPF(一)认识WPF-更新至Prism7.1
  • 原文地址:https://www.cnblogs.com/asuldb/p/11580578.html
Copyright © 2011-2022 走看看