日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

「模拟赛20180307」三元组 exclaim 枚举+树状数组

發布時間:2025/7/25 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 「模拟赛20180307」三元组 exclaim 枚举+树状数组 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目描述

給定 \(n,k\) ,求有多少個三元組 \((a,b,c)\) 滿足 \(1≤a≤b≤c≤n\)\(a + b^2 ≡ c^3\ (mod\ k)\)

輸入

多組數據,第一行數據組數\(T\)
每組數據兩個整數,\(n\)\(k\)

輸出

\(T\)行,每行一個整數,表示滿足條件的三元組的個數。

樣例

樣例輸入

1 10 7

樣例輸出

27 //為什么老被和諧啊

數據范圍

\(1≤n,k≤10^5\)
\(T≤400\)
時間限制\(4s\)

題解

與其他學校互測,然后做題感覺很不友好……
這道題數據很有特點(哪里很有特點了),\(10^5\)顯然是一個象征性的數字,它意味著\(O(n\ log\ n)\)是可以過的(這么大的\(T\)被無視了啊)。
那么很自然的想到,這個式子并沒有什么規律(我也很無奈啊),我們可以考慮枚舉\(a,b,c\)中的\(1\)個。
但是我們選擇哪一個比較好呢?容易想到,應該是\(c\),它的次數最高,不易計算。

接下來考慮一個簡化的問題,如果不取余\(k\),該怎么辦?
對于一個數\(b\),由于\(1≤a≤b\),顯然\(c^3\)只有在\([b^2+1,b^2+b]\)范圍內才有解,而且是唯一解。
所以每一個\(b\)可以為在\([b^2+1,b^2+b]\)\(c^3\)提供一個解,這不就是區間增加一個值嗎?樹狀數組即可做到。

再考慮取余\(k\)時,發現情況如出一轍,一樣的做就可以了。唯一一個問題就是,\([b^2+1,b^2+b]\)可能長度超過了\(k\)
這時能發現長度超過\(k\)后完全覆蓋了所有區域,任何一個\(c\)都可以使用這個\(b\),我們只需要一個計數器\(count\),每次增加\(\left \lfloor\frac{b}{k}\right \rfloor\)

現在,這道題的解法就呼之欲出了。我們從小到大枚舉\(c\),先在樹狀數組\((tree)\)\([c^2+1,c^2+c]\)的區間加上\(1\),并更新\(count\),答案就等于\(tree[c^3\%k]+count\)。時間復雜度為\(O(Tn\ log\ n)\)(再說一次請無視\(T\)的大小)

\(Code:\)

#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define N 100005 #define ll long long int T, n, mod; ll ans, now, t[N]; void update(int x, int v) {for (int i = x; i <= mod; i += i & -i)t[i] += v; } ll getsum(int x) {ll ans = 0;for (int i = x; i; i -= i & -i)ans += t[i];return ans; } int main() {freopen("exclaim.in", "r", stdin);freopen("exclaim.out", "w", stdout);scanf("%d", &T);for (int cas = 1; cas <= T; cas++){scanf("%d%d", &n, &mod);ans = now = 0;memset(t, 0, sizeof(t));for (int i = 1; i <= n; i++){int l =(1ll * i * i + 1)% mod + 1, r =(1ll * i * i + i)% mod + 1;if (l <= r)update(l, 1), update(r + 1, -1);elseupdate(1, 1), update(r + 1, -1), update(l, 1);int c = 1ll * i * i % mod * i % mod;now +=(i - 1)/ mod;ans += getsum(c + 1) + now;}printf("Case %d: ", cas);cout << ans;putchar(10);} }

最后的吐槽:\(exclaim\)并不是三元組的意思,是驚叫的意思……至于為什么,我也不知道……

轉載于:https://www.cnblogs.com/ModestStarlight/p/8528555.html

總結

以上是生活随笔為你收集整理的「模拟赛20180307」三元组 exclaim 枚举+树状数组的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。