上分難,上分難,上分路,今安在/ll
還好 E 題最后 5min 完成絕殺避免掉分。
一共 10 發罰時,菜的真實。
A - Water Pressure
輸出 \(\frac{x}{100}\) 即可。
B - Election
用 map 統計每個字符串的出現次數,然后暴力判斷一下哪個字符串出現次數最多
C - Counting 2
給你 \(n\) 個數, \(q\) 次詢問,每次詢問給定一個 \(x\) ,回答有多少個數 \(\ge x\) 。
\(1 \le n,q \le 2 \times 10^5\)
從小到大排完序,對於每次詢問,每次 lower_bound 一下第一個 \(\ge x\) 的位置 \(k\) ,這次詢問答案為 \(n-k+1\) 。
時間復雜度 \(\mathcal O((n+q)\log n)\)
D - Neighbors
給你 \(n\) 個點,要求將他們排成一個序列,但要求滿足 \(m\) 個關系。
對於每個關系 \((u,v)\) 表示 \(u\) 要和 \(v\) 相鄰。最后輸出能否在滿足所有關系的情況下排成一個序列。
首先對於每個點要滿足度數 \(\le 2\),還有一種情況是關系構成一個環也是不合法的。
判環可以直接用 dfs 或者 tarjan 。
E - Minimal payments
從前有一個國家,這個國家里有 \(n\) 種貨幣,第 \(1\) 種貨幣的面值為 \(a_i\)。
在這里,\(1 = a_1 < a_2 < ... < a_{n-1} < a_n\) ,並且對於每個 \(i \in [1,n)\) ,都滿足 \(a_{i+1}\) 是 \(a_i\) 的倍數。
現在你要支付 \(X\) 元,你要求出一種方案,使得支付的錢的張數和找回的錢的張數的和最少。
你只需要輸出這個和最小是多少。
\(1 \le n \le 60\), \(1 = a_1 < ... < a_n \le 10^{18}\),\(1 \le X \le 10^{18}\)
注意,對於每個 \(i \in [1,n)\) ,都滿足 \(a_{i+1}\) 是 \(a_i\) 的倍數。
\(n\) 的數據范圍很小,考慮 dfs ,因為后面一個數是前面一個數的倍數,我們考慮從前向后 dfs 或者從后往前 dfs 。
先說官方題解的做法
可以發現,所有可能出現的數值為 \(\lfloor \frac{X}{a_i} \rfloor\) 和 \(\lceil \frac{X}{a_i} \rceil\)。加上記憶化,總體復雜度為 \(\mathcal O(n)\) 。
具體方向是從后向前枚舉使用那種貨幣,你可以考慮將現在的 \(X\) 補成 \(Y \equiv 0 \pmod {a_i}\) 的情況,這樣你需要補的金額是 \(Y-X\),你也可以考慮把能用 \(a_i\) 支付的部分全部用 \(a_i\) 支付,最后剩下 \(X \% a_i\) 的金額需要支付。
在說一下我的卡常做法
你也可以從后向前搜,在使用了第 \(i\) 種貨幣后要保證 剩下的金額 $ % a_{i+1} = 0$ ,這樣的復雜度是 \(\mathcal O(2^{60})\) 。
然后我們加一點剪枝:
- 如果當前的答案已經超過了現有的最優的答案,直接返回。
- 如果
(double)clock()/CLOCKS_PER_SEC >= 1.98,直接輸出現有的答案退出程序。
只加第一個會 T 三個點,加了第二個之后就可以卡過去了。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int INF = 1e18 + 10;
int n, X, ans = INF;
int a[100];
void dfs(int pos, int sum, int cnt) {
if((double)clock()/CLOCKS_PER_SEC >= 1.98) cout << ans << "\n", exit(0);
if(cnt >= ans) return ;
if(pos == n) {
cnt = cnt + sum / a[n];
ans = min(ans, cnt);
return ;
}
int x = sum % a[pos + 1];
if(!x) dfs(pos + 1, sum, cnt);
else {
dfs(pos + 1, sum - x, cnt + x / a[pos]);
dfs(pos + 1, sum + a[pos + 1] - x, cnt + (a[pos + 1] - x) / a[pos]);
}
}
signed main() {
cin >> n >> X;
for(int i = 1; i <= n; ++i) cin >> a[i];
dfs(1, X, 0);
cout << ans << "\n";
return 0;
}
F - Jealous Two
給你 \(n\) 個物品,每個物品有兩個屬性 \(a_i, b_i\),求下面這個式子的值:
\[\sum_{i=1}^{n} \sum_{j=1}^{n} [a_i \ge a_j \&\& b_i \le b_j] \]\(1 \le n \le 2 \times 10^5, 0 \le a_i, b_i \le 10^9\) 。
一個經典的二位偏序問題。
首先對 \(b\) 數組排序,消除第二個限制。
然后就變成了求 \(a\) 數組的類似逆序對的問題。
對 \(a\) 數組離散化后上樹狀數組即可。
有兩點要注意:
- 當 \(i=j\) 時方案合法,所以最后的答案要 \(+ n\) ,(先修改在求和的寫法應該不需要)
- 當兩個物品的兩個值都相同是,不僅 \((i,j)\) 有貢獻 \((j,i)\) 也有貢獻,在外面單獨統計一下即可。
時間復雜度 \(\mathcal O(n \log n)\) 。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN = 2e5 + 10;
struct node {
int x, y;
bool operator < (const node &b) const { return y == b.y ? x > b.x : y < b.y; }
}a[MAXN];
int n, Cnt = 0, ans = 0;
int date[MAXN];
namespace Bit {
int sum[MAXN];
int lb(int x) { return x & -x; }
void Modify(int x, int k) { for(; x <= Cnt; x += lb(x)) sum[x] += k; }
int Query(int x) { int res = 0; for(; x; x -= lb(x)) res = res + sum[x]; return res; }
}
signed main() {
cin >> n;
for(int i = 1; i <= n; ++i) cin >> a[i].x, date[i] = a[i].x;
for(int i = 1; i <= n; ++i) cin >> a[i].y;
sort(a + 1, a + n + 1);
int cnt = 1;
for(int i = 1; i <= n; ++i) {
if(a[i].x != a[i + 1].x || a[i].y != a[i + 1].y)
ans = ans + (cnt * cnt - cnt) / 2, cnt = 1;
else cnt ++;
}
sort(date + 1, date + n + 1), date[0] = -1000;
for(int i = 1; i <= n; ++i) if(date[i] != date[i - 1]) date[++Cnt] = date[i];
for(int i = 1; i <= n; ++i) a[i].x = lower_bound(date + 1, date + Cnt + 1, a[i].x) - date;
for(int i = 1; i <= n; ++i) {
int cnt = Bit::Query(Cnt) - Bit::Query(a[i].x - 1);
Bit::Modify(a[i].x, 1);
ans = ans + cnt;
}
printf("%lld\n", ans + n);
return 0;
}
G - Balls in Boxes
[G - Balls in Boxes] [題解]
切隊說他是 GF (生成函數?)板子,反正我不會生成函數,題解也沒看懂。
H - Minimum Coloring
貌似是網絡流最大匹配之類的?
