bzoj_2154: Crash的数字表格 (自己想了70分)
有两个注意的地方:
1.预处理到max(n,m)max(n,m)的范围就行了,要不在大视野上超时
2. (x+1)*x/2*(y+1)*y/2 在中间会炸long long,记得在中间mod
自己的n<=1000000做法:
主要的限制是我的因为要除一个东西,没法线性筛,只能log筛,n>2000000就会超时
ans=n∑i=1m∑j=1lcm(i,j)ans=n∑i=1m∑j=1lcm(i,j)
ans=n∑i=1m∑j=1i∗jgcd(i,j)ans=n∑i=1m∑j=1i∗jgcd(i,j)
这是题意
我的是 设f(i) 为 gcd(x,y)==i的x*y的和 F(i) 为i|gcd(x,y) 的x*y的和
反演后
f(i)=∑i|dμ(di)F(d),其中另x=⌊ni⌋,y=⌊mi⌋F(i)=i2(x+1)∗x/2∗(y+1)∗y
ans=min(n,m)∑d=1x∗(x+1)∗y∗(y+1)∑i|dμ(di)4∗i
但是渊哥说后面的那个东西分母不是积性函数,不能线性筛..
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; inline int read() { char q=getchar();int ans=0; while(q<'0'||q>'9')q=getchar(); while(q>='0'&&q<='9'){ans=ans*10+q-'0';q=getchar();} return ans; } const int mod=20101009; const int N=2000006; int prime[N],cnt; bool he[N]; int mu[N]; ll ni[N],ji[N]; void chu() { ni[1]=1; for(int i=2;i<N;++i) ni[i]=(ll)(mod-mod/i)*ni[mod%i]%mod; mu[1]=1;//ji[1]=1; for(int i=2;i<N;++i) { if(!he[i]) { prime[++cnt]=i; mu[i]=-1; //ji[i]=(ni[i]-1+mod)%mod; } for(int j=1;j<=cnt&&prime[j]*i<N;++j) { he[i*prime[j]]=1; if(i%prime[j]==0) { mu[i*prime[j]]=0; //ji[i*prime[j]]=ji[i]*ni[prime[j]]%mod; break; } //ji[i*prime[j]]=ji[i]*ji[prime[j]]%mod; mu[i*prime[j]]=-mu[i]; } } for(int i=1;i<N;++i) for(int j=i;j<N;j+=i) ji[j]=(ji[j]+mu[j/i]*ni[i]%mod*ni[4]%mod*j%mod*j%mod+mod)%mod; for(int i=1;i<N;++i) ji[i]=((ji[i]+ji[i-1])%mod+mod)%mod; } int n,m; ll work() { if(n>m) swap(n,m); ll ans=0,tt; int nx; for(int i=1;i<=n;i=nx+1) { nx=min( n/(n/i),m/(m/i) ); tt=(ll)(n/i+1)%mod*(n/i)%mod*(m/i)%mod*(m/i+1)%mod; ans=(ans+tt*(ji[nx]-ji[i-1]+mod)%mod)%mod; } return (ans+mod)%mod; } int main(){ freopen("in.in","r",stdin); //freopen("nt2011_table.in","r",stdin); //freopen("nt2011_table.out","w",stdout); chu(); scanf("%d%d",&n,&m); cout<<work(); }
然后我就怂题解了
正解:
ans=n∑i=1m∑j=1i∗jgcd(i,j)
ans=min(n,m)∑d=1d2∗f(⌊nd⌋,⌊md⌋)d
f(x,y) 为gcd(x,y)==1的x*y的和,反演后
f(x,y)=min(n,m)∑d=1d2μ(d)Sum(⌊xd⌋,⌊yd⌋)
Sum(x,y)=(x+1)∗x/2∗(y+1)∗y/2
然后就是O(√n√n)
用到的思想就是把求gcd(x,y)==d转化成了求
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; inline int read() { char q=getchar();int ans=0; while(q<'0'||q>'9')q=getchar(); while(q>='0'&&q<='9'){ans=ans*10+q-'0';q=getchar();} return ans; } const int mod=20101009; const int N=10000006; int prime[N],cnt; bool he[N]; int mu[N]; ll pr1[N],pr2[N]; int n,m; void chu() { int q1=max(n,m); mu[1]=1; for(int i=2;i<=q1;++i) { if(!he[i]) { prime[++cnt]=i; mu[i]=-1; } for(int j=1;j<=cnt&&prime[j]*i<=q1;++j) { he[i*prime[j]]=1; if(i%prime[j]==0) { mu[i*prime[j]]=0; break; } mu[i*prime[j]]=-mu[i]; } } for(int i=1;i<=q1;++i) { pr1[i]=(pr1[i-1]+i)%mod; pr2[i]=(pr2[i-1]+((ll)mu[i]*i%mod*i%mod)+mod)%mod; } } ll sum(ll x,ll y) { return ( ((x+1)*x/2%mod) * ((y+1)*y/2%mod) )%mod; } ll f(int x,int y) { if(x>y) swap(x,y); ll ans=0; int nx; for(int i=1;i<=x;i=nx+1) { nx=min( x/(x/i),y/(y/i) ); ans=(ans+sum(x/i,y/i)*(pr2[nx]-pr2[i-1]+mod)%mod)%mod; //nx=min( x/(x/i),y/(y/i) ); //ans=(ans+((x/i+1)*(x/i)/2)*((y/i+1)*(y/i)/2)%mod*(pr2[nx]-pr2[i-1]+mod)%mod)%mod; } return (ans+mod)%mod; } ll work() { if(n>m) swap(n,m); ll ans=0; int nx; for(int i=1;i<=n;i=nx+1) { nx=min( n/(n/i),m/(m/i) ); ans=(ans+(pr1[nx]-pr1[i-1]+mod)%mod*f(n/i,m/i))%mod; } return (ans+mod)%mod; } int main(){ //freopen("in.in","r",stdin); //freopen("nt2011_table.in","r",stdin); //freopen("nt2011_table.out","w",stdout); scanf("%d%d",&n,&m); chu(); cout<<work(); }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 你所不知道的 C/C++ 宏知识
· 聊一聊 操作系统蓝屏 c0000102 的故障分析
· SQL Server 内存占用高分析
· .NET Core GC计划阶段(plan_phase)底层原理浅谈
· .NET开发智能桌面机器人:用.NET IoT库编写驱动控制两个屏幕
· 我干了两个月的大项目,开源了!
· 推荐一款非常好用的在线 SSH 管理工具
· 千万级的大表,如何做性能调优?
· 盘点!HelloGitHub 年度热门开源项目
· Phi小模型开发教程:用C#开发本地部署AI聊天工具,只需CPU,不需要GPU,3G内存就可以运行,