题解 CF1146D 【Frog Jumping】

ChthollyTree

2019-04-22 09:14:21

Solution

应该可以想到一个O(n) 的做法 求出 $\sum_{i=1}^{n}f(i)$ 就是bfs,每次加入一个点i是时候,判断之前 i-a 是否之前可以到达 如果可以,那么点i可以到达,并用点i bfs扩展一波即可 这样每个点最多被遍历1次,所以是O(n)的 ------------ 然后我们打表找规律,发现当 n > 2*max(a,b)的时候,f(n) = $\frac{n}{gcd(a,b)}+1$ 然后在 $i <= 2*max(a,b)$ 时暴力做,否则用规律就行了 比赛的时候其实我找到规律了,但是忘记了小数据可以暴力做这种操作,一直推式子 直到最后10min我才做出来这题。我太菜了 不过总算让 [ChthollyTree](https://codeforces.com/profile/ChthollyTree) 上紫了 ``` #include<bits/stdc++.h> using namespace std; #define int long long #define LL long long #define INF (LL)(0x3f3f3f3f)*(LL)0x3f3f3f3f #define MAXN 300005 LL n,m; LL a,b,x; LL ans = 0; LL an[MAXN]; bool f[MAXN]; queue<int>q; LL gcd(LL x,LL y) { if(x%y != 0) return gcd(y,x%y); return y; } LL orz(LL x) { return x*(x+1)>>1; } LL sqz(LL x,LL mo) { if(x % mo == 0) return x/mo; else return x/mo+1; } LL stO(LL n) { return orz((n+1)/x)*x + ((n+1)%x)*(sqz(n+1,x)); } int bfs(int i) { int ans = 0; f[0] = 1; while(!q.empty()) { int x = q.front(); q.pop(); ans ++; if(x+a <= i && !f[x+a]) { f[x+a] = 1; q.push(x+a); } if(x-b >= 0 && !f[x-b]) { f[x-b] = 1; q.push(x-b); } } return ans; } signed main() { cin >> n >> a >> b; q.push(0); an[0] = 1; f[0] = 1; bfs(0); for(int i = 1; i <= max(a,b)*2; i ++) { if(i-a >= 0 &&f[i-a]) { f[i] = 1; q.push(i); an[i] = an[i-1]+bfs(i); } else { an[i] = an[i-1]; } } x = gcd(a,b); if(a > b) swap(a,b); for(int i = 0; i < min(n+1,2*b); i ++) { ans += an[i]; } if(n >= 2*b) ans += stO(n) - stO(2*b-1); } cout<<ans; return 0; } ```