2021"MINIEYE杯"中超(3)補題
阿新 • • 發佈:2021-08-03
2021"MINIEYE杯"中超(3)
1003 Forgiving Matching
不會fft,會了再補
1004 Game on Plane
首先兩條直線存在交點當且僅當兩條直線斜率不同,所以Alice的最優策略就是最小化斜率出現次數最多的數目,Bob的最優策略就是畫一條斜率是出現次數最多的斜率的直線。所以Alice策略就是不斷從各種斜率的直線中各取一條即可。
記住特判一下斜率不存在和斜率是負數的負號歸屬的情況,還有因為存的是(y2 - y1) / (x2 - x1),存的時候還要將其化簡。
#include <bits/stdc++.h> using namespace std; typedef pair<int, int> PII; int t; int n; int gcd(int a, int b) { return b ? gcd(b, a % b) : a; } void solve() { map<PII, int> m; int x1, x2, y1, y2;//莫名其妙這一句放到全域性變數就報錯。。。 cin >> n; for (int i = 1; i <= n; i ++ ) { cin >> x1 >> y1 >> x2 >> y2; int x = x2 - x1, y = y2 - y1; bool flag = ((x < 0) ^ (y < 0)); if (x < 0) x = -x; if (y < 0) y = -y; if (flag) x = -x;//如果斜率是負的,為方便統計把負號放在x的位置 PII temp; if (x == 0)//斜率不存在 temp = make_pair(0, 1); else if (y == 0)//斜率為0 temp = make_pair(1, 0); else { int u = gcd(x, y); temp = make_pair(x / u, y / u);//約分 } if (!m[temp]) m[temp] = 1; else m[temp] ++ ;//統計個數 } vector<int> v; for (map<PII, int>::iterator it = m.begin(); it != m.end(); it ++ ) v.push_back(it -> second); sort(v.begin(), v.end(), greater<int>());//從大到小排序 //for (auto t : v) cout << t << ' '; cout << endl; int len = v.size();//cout << len << endl; int ans = 0; int pos = 0; for (int i = 1; i <= n; i ++ ) { if (!v[pos] || pos == len) pos = 0, ans ++ ;//如果有一種用光了或者每一種都用過了,那麼必定要重複 printf("%d\n", i - ans - 1); v[pos] -- ; pos ++ ; } } int main() { ios::sync_with_stdio(0);cin.tie(0); cin >> t; while (t -- ) solve(); return 0; }
1009 Rise in Price
題目大意:從(1, 1)走到(n, n),取走路徑上的所有數,求(∑a_i_j) * (∑b_i_j)的最大值。首先考慮dpf[i, j, k]表示走到了[i, j]點,拿了k個鑽石,此時價格上漲了f[i, j, k],但是由於k取值過大,dp空間不夠。所以不可以用這種常規的dp。
接著考慮,dp的每個狀態都存的是每種情況的最優解,所以才導致空間使用過大,換種思路,[i, j]這個點的狀態取決於[i - 1, j]和[i, j - 1],我們從中一定是取比較優的狀態,所以我們每個位置開一個vector,從前面的位置繼承狀態後根據本題要求按照優劣排序,儲存一部分狀態,然後擇優繼承,區域性最優來達到全域性最優。
注意事項:1.開longlong 2.每次都要clear一下vector 3.不要用for(auto)賦值!因為這個錯誤debug了好久。。。
#include <bits/stdc++.h> #define x first #define y second using namespace std; typedef long long LL; typedef pair<LL, LL> PLL; const int N = 110; vector<PLL> v[N][N]; int t; int n; LL a[N][N], b[N][N]; bool cmp(PLL a, PLL b) { return a.x * a.y > b.x * b.y; } void solve() { cin >> n; for (int i = 1; i <= n; i ++ ) for (int j = 1; j <= n; j ++ ) { cin >> a[i][j]; v[i][j].clear(); } for (int i = 1; i <= n; i ++ ) for (int j = 1; j <= n; j ++ ) cin >> b[i][j]; //for (int i = 1; i <= n; i ++ ) for (int j = 1; j <= n; j ++ ) cout << a[i][j] << (j == n ? '\n' : ' '); //for (int i = 1; i <= n; i ++ ) for (int j = 1; j <= n; j ++ ) cout << b[i][j] << (j == n ? '\n' : ' '); for (int i = 1; i <= n; i ++ ) for (int j = 1; j <= n; j ++ ) { if (i == 1 && j == 1)//左上角直接繼承自己 { v[i][j].push_back(make_pair(a[i][j], b[i][j])); continue; } else if (i == 1) v[i][j].push_back(v[i][j - 1][0]); else if (j == 1) v[i][j].push_back(v[i - 1][j][0]); else { int p1 = 0, p2 = 0;//指標 while (v[i][j].size() < 100)//取大概100個狀態擇優轉移 { if (p1 < v[i - 1][j].size() && p2 < v[i][j - 1].size())//兩個狀態都還可以轉移 { if (v[i - 1][j][p1].x * v[i - 1][j][p1].y > v[i][j - 1][p2].x * v[i][j - 1][p2].y)//擇優 { v[i][j].push_back(v[i - 1][j][p1]); p1 ++ ; } else v[i][j].push_back(v[i][j - 1][p2]), p2 ++ ; } else if (p1 < v[i - 1][j].size())//掃尾 { v[i][j].push_back(v[i - 1][j][p1]); p1 ++ ; } else if (p2 < v[i][j - 1].size()) { v[i][j].push_back(v[i][j - 1][p2]); p2 ++ ; } else break;//都繼承完了 } } for (int k = 0; k < v[i][j].size(); k ++ ) v[i][j][k].x += a[i][j], v[i][j][k].y += b[i][j];//加上當前格子的值 //for (auto t : v[i][j]) t.x += a[i][j], t.y += b[i][j];//這種寫法錯誤,值並沒有賦過去!!! sort(v[i][j].begin(), v[i][j].end(), cmp);//根據優劣排序 } cout << v[n][n][0].x * v[n][n][0].y << endl; } int main() { ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); cin >> t; while (t -- ) solve(); return 0; }
1011 Segment Tree with Pruning
線段樹最多有log種長度,所以直接記憶化搜尋就行。要注意每次都要把map清空。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int t;
LL n, k;
map<LL, LL> m;
LL build(LL l, LL r)
{
if (m.count(r - l)) return m[r - l];//如果這個段已經計算過了,不用再計算,直接返回
if (r - l + 1 <= k) return 1;//區間不可以再分了
LL mid = l + r >> 1, cnt = 1;
cnt += build(l, mid) + build(mid + 1, r);
return m[r - l] = cnt;
}
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin >> t;
while (t -- )
{
cin >> n >> k;
m.clear();//清空map
cout << build(1, n) << endl;
}
return 0;
}