魔板(商之和)

  • 思路:最多2sqrt(n)种值,因此值是一段一段出现的。
    可以通过出现的任意一个点x,推出该段的r(右端点)
  • 代码:(很短)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
	ll ans=0,n;
	scanf("%lld",&n);
	for(ll l=1,r=1;l<=n&&r<=n;l=r+1) {
		r=min(n,n/(n/l));
		ans+=(r-l+1)*(n/l);
	}
	printf("%lld",ans);
	return 0;
}

余数之和

  • 思路:转化一下,不要除零。要用等差数列求和。
  • 代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
	ll n,k,sum=0;
	scanf("%lld%lld",&n,&k);
	for(ll l=1,r=1;l<=min(k,n)&&r<=min(k,n);l=r+1) {
		r=min(min(k,n),k/(k/l));
		sum+=(l+r)*(r-l+1)/2*(k/l);
	}
	printf("%lld",n*k-sum);
	return 0;
}

tmp1

  • 题意: sum((a/i)+(b/i))
  • 双魔板,最多有2*[sqrt(a)+sqrt(b)]种值(复杂度出来了),维护四个指针即可

tmp2

  • 题意:魔板改为上取整
  • 思路:a/i=(a+i-1)/i=(a-1)/i+1【分离常数,期末考试材料题数学挂科就是因为这个没分离常数,浪费枚举时间】

模积和(算难亿点的)

  • 题意:sum{(n mod i)*(m mod j)} [i->[1,n] ; j->[1,m] ]
    水不水?
    不过,i!=j,呵呵
  • 思路:
    1.原上式-(i=j时的式子)
    2.转化mod->"/"
    3.乘法分配率+分离常数
    4.反正式子就超级恶心:既用到魔板,又用到tmp1,余数之和。
    总之思维难度不是太大,代码复杂。
  • 代码:
#include<stdio.h>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll mod=19940417;
ll Ps(ll n) {
	n%=mod;
	if(n%3==0||(n+1)%3==0) return n*(n+1)/6%mod*(2*n+1)%mod;
	else return n*(n+1)/2%mod*(2*n+1)/3%mod;
}
int main() {
	ll n,m,sumn=0,summ=0,sum1=0,sumnm=0;
	scanf("%lld%lld",&n,&m);
	if(n>m) swap(n,m);
	for(ll l=1,r=1;l<=n;l=r+1) {
		r=min(n,n/(n/l));
		sumn+=(l+r)*(r-l+1)/2%mod*(n/l)%mod;
		sumn%=mod;
	}
	for(ll l=1,r=1;l<=m;l=r+1) {
		r=min(m,m/(m/l));
		summ+=(l+r)*(r-l+1)/2%mod*(m/l)%mod;
		summ%=mod;
	}
	for(ll l=1,r,r1,r2;l<=n;l=r+1) {
		r1=n/(n/l),r2=m/(m/l);
		r=min(min(r1,r2),n);
		sum1+=(n/l)*(m/l)%mod*(Ps(r)-Ps(l-1)+mod)%mod;
	}
	for(ll l=1,r;l<=n;l=r+1) {
		r=min(n,m/(m/l));
		sumnm+=(l+r)*(r-l+1)/2%mod*(m/l);
		sumnm%=mod;
	}
	ll ans= (n*n%mod-sumn)%mod*(m*m%mod-summ)%mod - ((n*n%mod*m%mod-m*sumn%mod-n*sumnm%mod+sum1)%mod+mod)%mod;
	printf("%lld",(ans%mod+mod)%mod);
	return 0;
}