1 条题解

  • 0
    @ 2025-8-24 22:33:23

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar whileAK
    **

    搬运于2025-08-24 22:33:23,当前版本为作者最后更新于2024-08-16 17:17:45,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    P7819 [RC-05] Xor Matrix

    思路

    kk 进制下的异或每一位都是独立的。考虑枚举每一位 pp,这位的贡献就是矩形内所有数的第 pp 位数字之和再对 kk 取模,最后乘上 kpk^p。对于以 (x,y)(x,y) 为左上角,(z,w)(z,w) 为右下角的矩形,可以用容斥把左上角改成 (1,1)(1,1),则第 pp 位的答案是:

    $$\sum_{i=1}^{z}\sum_{j=1}^{w} \lfloor \frac{(i-1)m+j}{k^p}\rfloor $$

    kk 取模。上式相当于:

    $$\sum_{i=1}^{z}\sum_{j=0}^{w-1} \lfloor \frac{j+(i-1)m+1}{k^p}\rfloor $$

    这样第二个循环就可以用类欧 O(1)O(1) 算。不会类欧的可以点这里。这样我们只用枚举 ii,总复杂度 O(qnlogV)O(qn\log{V})

    然而 nn 可能很大,能达到 101010^{10},但 nmnm 也才 101010^{10},当 nn 很大时 mm 很小。我们想再推一个枚举 mm 的式子,在 nn 很大时枚举 mm。只要交换求和符号就好了:

    $$\sum_{j=1}^{w}\sum_{i=0}^{z-1} \lfloor \frac{im+j}{k^p}\rfloor $$

    也可以用类欧做,但算第二个式子需要 O(logn)O(\log{n}) 而不是 O(1)O(1)。所以总复杂度 O(qmin(n,m)logVlogn)O(q\min{(n,m)}\log{V}\log{n})

    注意

    1、本题卡常,请适当使用卡常技巧。注意第一种情况复杂度优于第二种情况,第一种情况可以在 z106z\le10^6 时用,第二种情况可以在 w104w\le10^4 时用。

    2、类欧中有需要除以 22 的式子,由于模数 kk 没有限制,所以不一定有逆元,需要特殊处理。

    3、全部开 long long,必要时开 __int128,计算过程中可能爆 long long。

    Code:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    void rd(int &p){
    	p=0;int f(0);char z=getchar();
    	while(z>'9'||z<'0'){if(z=='-')f^=1;z=getchar();}
    	while(z>='0'&&z<='9')p=(p<<1)+(p<<3)+z-'0',z=getchar();
    	if(f)p=-p;
    }
    void rdl(ll &p){
    	p=0;int f(0);char z=getchar();
    	while(z>'9'||z<'0'){if(z=='-')f^=1;z=getchar();}
    	while(z>='0'&&z<='9')p=(p<<1)+(p<<3)+z-'0',z=getchar();
    	if(f)p=-p;
    }
    const ll N=1e10;
    ll k;
    inline ll f(ll a,ll b,ll c,ll n){
    	if(n<0)return 0ll;
    	ll bc=b/c,n1=n+1ll,n2;
    	if(n&1ll)n2=(__int128)n1/2ll*n%k;
    	else n2=(__int128)n/2ll*n1%k;
    	ll ans=n2*(a/c)%k+n1%k*bc%k;
    	a%=c;b%=c;
    	if(!a)return (n1%k*(b/c)+ans)%k;
    	ll abc=floor(1.0*(a*n+b)/c);
    	return (ans%k+n%k*(abc%k)%k-f(c,c-b-1ll,a,abc-1ll)+k)%k;
    }
    ll n,m,q;
    inline ll ask1(ll z,ll w,ll kp){
    	ll ans(0);
    	if(w<=10000)
    	for(ll j(1);j<=w;++j){
    		ans+=f(m,j,kp,z-1);
    	}
    	else{
    		for(ll i(1);i<=z;++i){
    			ans+=f(1,(i-1)*m+1,kp,w-1);
    		}
    	}
    	return ans%k;
    }
    ll x,y,z,w,ans;
    int main(){
    	rdl(n);rdl(m);rdl(q);
    	while(q--){ans=0;
    		rdl(x),rdl(y),rdl(z),rdl(w),rdl(k);
    		for(ll p(1);p<=n*m;p*=k){
    			ans+=p*((ask1(z,w,p)-ask1(z,y-1,p)-ask1(x-1,w,p)+ask1(x-1,y-1,p)+2*k)%k);
    		}printf("%lld\n",ans);
    	}
    	return 0;
    }
    • 1

    信息

    ID
    6589
    时间
    6000ms
    内存
    512MiB
    难度
    7
    标签
    递交数
    0
    已通过
    0
    上传者