首先你得看懂题目以及它给你的图。“‘第 (x) 个月的第 (y) 天’ 与 ‘第 (y) 个月的第 (x) 天’ 在它的那周的同一天“怎么理解?
”第 (x) 个月的第 (y) 天“ 转换为 “总共第 ((x-1)d + y) 天”,“第 (y) 个月的第 (x) 天“ 转换为 “总共第 ((y-1)d + x) 天”。
同时,可以发现“在它的那周 的同一天”时,两个天数是模 (w) 同余的。
也就是说,当 (1 leq x,y leq min(m,d)) 时,
注意到 ((x-1)d) 实质上是 (dx - d) , ((y-1)d) 实质上是 (dy - d) ,约去 (-d) ,可得
移项,得
(d-1) 和 (w) 可能不是互质的。考虑令它们互质,把它们除以 (gcd(d-1,w)),得到新的 (D) 和 (w')((D = frac{d-1}{gcd(d-1,w)}),(w' = frac{w}{gcd(d-1,w)})),这样就可以保证 (x < w') 时,(Dx mod w') 互不相同。这样就可以光明正大地消去 (D) 了。
记 (min(m,d)) ((d) 是原先的,不是大写) 为 (lim)。如果 (lim) 比较小,可以直接枚举余数 (r) ,计算出 ([1,lim]) 中满足 (k mod w') 的 (k) 的数量 (num),它的贡献为 (frac{num(num-1)}{2})。这里 (lim) 可能很大,换个做法,我们发现 (num) 的取值只有两种情况。
(num = lfloor frac{lim}{w'} floor) ,有 ((w' - (lim mod w'))) 组;
(num = lfloor frac{lim}{w'} floor + 1) ,有 ((lim mod w')) 组。
两种累加起来就好了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mit map<int,int>::iterator
#define sit set<int>::iterator
#define itrm(g,x) for(mit g=x.begin();g!=x.end();g++)
#define itrs(g,x) for(sit g=x.begin();g!=x.end();g++)
#define ltype int
#define rep(i,j,k) for(ltype(i)=(j);(i)<=(k);(i)++)
#define rap(i,j,k) for(ltype(i)=(j);(i)<(k);(i)++)
#define per(i,j,k) for(ltype(i)=(j);(i)>=(k);(i)--)
#define pii pair<int,int>
#define fi first
#define se second
#define mpr make_pair
#define pb push_back
#define fastio ios::sync_with_stdio(false)
const int inf=0x3f3f3f3f,mod=1000000007;
const double pi=3.1415926535897932,eps=1e-6;
void chmax(int &x,int y){if(x < y) x = y;}
void chmin(int &x,int y){if(x > y) x = y;}
int T,m,d,w;
int gcd(int x,int y){
if(!y) return x;
return gcd(y, x%y);
}
ll f(ll x){
return x * (x-1) / 2;
}
int main()
{
fastio;
cin>>T;
while(T--) {
cin>>m>>d>>w;
int k = gcd(d - 1, w);
int w1 = w / k, lim = min(d, m);
ll A = ll(lim % w1) * f(lim / w1 + 1), B = ll(w1 - lim % w1) * f(lim / w1);
cout<<A+B<<'
';
}
return 0;
}