CodeForces 1389E Calendar Ambiguity 题解
首先你得看懂题目以及它给你的图。“‘第 \(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'} \rfloor\) ,有 \((w' - (lim \mod w'))\) 组;
\(num = \lfloor \frac{lim}{w'} \rfloor + 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<<'\n';
}
return 0;
}