洛谷P3791:普通数学题(整除分块、前缀和)
                                                            生活随笔
收集整理的這篇文章主要介紹了
                                洛谷P3791:普通数学题(整除分块、前缀和)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.                        
                                解析
似乎位運算和易或并沒有太多性質上的聯系…
 所以換個角度分析
考慮按照二進制進行類似數位dp
 暴力枚舉 i 和 j 的前k,p位與n、m相同,下一位比n、m小。
 然后后面的東西就可以隨便填
 每個異或的結果都有2^(兩個數都可以隨便填的位數)的方案
 然后乘上一個約數個數前綴和的差分即可
 由于n和m的二進制表示確定,需要求的前綴和的個數其實是O(logn)級別的
 利用map記憶化一下可以做到n?log?n\sqrt n*\log nn??logn
 能夠通過本題
代碼
#include<bits/stdc++.h> using namespace std; #define ll long long #define il inline const int N=200050; const int mod=998244353; inline ll read(){ll x=0,f=1;char c=getchar();while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}while(isdigit(c)){x=x*10+c-'0';c=getchar();}return x*f; } ll n,m,x; map<ll,ll>mp; ll mi[80]; ll calc(ll x){if(x<=0) return 0;if(mp.count(x)) return mp[x];ll ans=0;for(ll l=1,r;l<=x;l=r+1){r=x/(x/l);(ans+=1ll*(r-l+1)*(x/l))%=mod;}return mp[x]=ans; } int main(){#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);#endifmi[0]=1;for(int i=1;i<=40;i++) mi[i]=mi[i-1]<<1;n=read();m=read();x=read();++m;++n;ll res=0;for(int i=0;i<=40;i++){if((mi[i]&n)==0) continue;for(int j=0;j<=40;j++){if((mi[j]&m)==0) continue;int mn=min(i,j),mx=max(i,j);ll pre=(n^m^x^mi[i]^mi[j])&(mi[40]-mi[mx]);res+=((calc(pre+mi[mx]-1)-calc(pre-1)+mod)%mod*mi[mn])%mod;res%=mod;//printf("i=%d j=%d pre=%lld (%lld %lld) res=%lld\n\n",i,j,pre,pre+mi[mx]-1,pre-1,res);}}printf("%lld\n",res);return 0; } /*14 3 1 22 7 5 03 4 -10 19 10 1 0 */總結
以上是生活随笔為你收集整理的洛谷P3791:普通数学题(整除分块、前缀和)的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 在那看电脑的配置参数(在那看电脑的配置)
- 下一篇: 10.31模拟:总结
