题意:
给定m,d,w,
表示有m个月,每个月有d天,每周有w天
问有多少个数对(x,y),满足x<y,且第x个月的第y天与第y个月的第x天,星期相同
数据范围:m,d,w<=1e9
解法:
计算第x个月的第y天是周几:((x-1)d+y)%w+1
根据题目可以列出式子:(x-1)d+y=(y-1)d+x (%w)
转化一下得:(y-x)(d-1)%w=0
那么(y-x)(d-1)必须是w的倍数
因为(y-x)是变量,(d-1)和w是常量,所以(d-1)和w可以再约一下,
那么可以将(d-1)和w同时除以gcd(d-1,w),这样w更小,(y-x)的可选取范围更大
设g=gcd(d-1,w),那么(y-x)((d-1)/g)%(w/g)=0
现在(d-1)/g和w/g是互质的,要想令式子成立,只能让(y-x)是(w/g)的倍数
要注意的点:
因为可能存在第x月第y天,但是不存在第y月第x天,
所以x和y不能超过min(n,d),令m=min(n,d)
则x,y<=m
令w1=w/gcd(d-1,w)
1.当y=m时:
因为y>x且x最小为1,那么y的范围为[2,m],(y-x)的范围为[1,m-1],贡献为(m-1)/w1
2.当y=m-1时:
同上,(y-x)的范围为[1,m-2],贡献为(m-2)/w1
...
贡献最少的时候是w1/w1,因为如果y的取值再向下,贡献就是0了
最后答案肯定是k,k,.....2,2,2,1,1,1,的形式
发现有很多(m-kk)/w1是相同的,例如w1/w1与(2*w1-1)/w1是相同的,
[w1,2*w1-1]区间长度为w1,也就是说有若干段长度为w1的贡献相同,
显然只有数值最大的最后一段(上面的k,k,..那段)可能不为w1个,前面每一段都是w1个
最后一段的个数为m%w1
为啥是m不是(m-1)呢?
例如:
0,1,2除3等于0,
3,4,5除3等于1,
...
9,10除3等于3
虽然10%3等于1,而实际上[0,10]有11个数,所以应该是11%3,最后答案为2
(可能这样麻烦了,但是我不知道怎么推导才比较正常)
如果m%w1=0,说明全部都是w1个
否则假设f=m%w1,最后一组是f个,其他都是w1个
总贡献用等差数列公式计算一下即可
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=1e5+5;
int n,d,w;
signed main(){
int T;cin>>T;
while(T--){
cin>>n>>d>>w;
w/=__gcd(d-1,w);
int m=min(n,d);
//
int ans=0;
int t=m%w;
if(t==0){//全部都是w个
int tt=(m-1)/w;
ans+=tt*(tt+1)/2*w;
}else{//最后一段t个,其他都是w个
int tt=(m-1)/w;
ans+=(tt-1)*tt/2*w;
ans+=t*tt;
}
cout<<ans<<endl;
}
return 0;
}