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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

2021“MINIEYE杯”中国大学生算法设计超级联赛(1)个人解题报告

發布時間:2023/12/20 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 2021“MINIEYE杯”中国大学生算法设计超级联赛(1)个人解题报告 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • HDU6950 Mod, Or and Everything
    • HDU6954 Minimum spanning tree
    • HDU6958 KD-Graph
    • HDU6957 Maximal submatrix
    • HDU6955 Xor sum

中超聯賽

CSL中超可沒巨佬們訓練強度大

“什么是BSGS、莫隊、KD tree”

我看我是完全不懂噢

HDU6950 Mod, Or and Everything

題意

(nmod1)∣(nmod2)∣...∣(nmod(n?1))(n\ mod\ 1)|(n\ mod \ 2)|...|(n\ mod\ (n-1))(n?mod?1)(n?mod?2)...(n?mod?(n?1))的值

分析

打比賽時,

隊友:經過化簡可以得到答案為2k?12^k-12k?1

我:觀察樣例可以得到答案為2k?12^k-12k?1

QAQ

而實際上std的思路:nmodi≤?n2??1n\ mod\ i \leq \lceil \frac{n}{2}\rceil-1n?mod?i?2n???1,所以nmod(n?i)=in\ mod\ (n-i)=in?mod?(n?i)=i

所以這個和值就是000?n2??1\lceil \frac{n}{2}\rceil-1?2n???1的所有整數的和. 求出來是2k?12^k-12k?1,這里的kkk是某個帶nnn的式子,懶得認真推的話可以根據樣例猜出,是令n=2xn=2^xn=2x,這個xxx向下取整再減1得到kkk. 但如果xxx本來就是整數,那么xxx還要再減去1.(總之看代碼吧,或者去看std代碼)

代碼

#include <bits/stdc++.h> #define fors(i, a, b) for(int i = (a); i <= (b); ++i) #define lson k<<1 #define rson k<<1|1 #define pb push_back #define lowbit(x) ((x)&(-(x))) #define mem(a) memset(a, 0, sizeof(a)) #define DDLC_ESCAPE_PLAN_FAILED ios::sync_with_stdio(false), cin.tie(0) #define int long long const int inf = 0x3f3f3f3f; const double dinf = 1e100; typedef long long ll; //const ll linf = 9223372036854775807LL; // const ll linf = 1e18; using namespace std;signed main() {DDLC_ESCAPE_PLAN_FAILED;int t;cin >> t;while(t--){int n;cin >> n;int x = 0, res = n;while(res){res >>= 1LL;x++;}if(n == 1LL){cout << 0 << endl;continue; }if(n == (1LL << (x - 1LL))) x--;cout << (1LL << (x - 1LL)) - 1LL << endl;}return 0; }

HDU6954 Minimum spanning tree

題意

有一個n?1n-1n?1個節點的帶權完全圖,節點標記為2,3,...,n2,3,...,n2,3,...,n. 完全圖中從點iii到點jjj的邊的權值大小為lcm(i,j)lcm(i,j)lcm(i,j),請你求出這個圖的最小生成樹。n≤10000000n\leq 10000000n10000000.

分析

容易知道,對任何一個邊(i,j)(i,j)(i,j),這個邊的權值不會小于max(i,j)max(i,j)max(i,j).

那么對于一個合數,它連向自己的因子即可,這時候邊的權值就是這個合數。由于因子一定比自己小,所以在2,3,..i2,3,..i2,3,..i中一定存在。

而對于一個質數xxx,和任意一點iii相連,都有lcm(x,i)=x?ilcm(x,i)=x·ilcm(x,i)=x?i. 故令iii最小,取2即可保證邊權最小。

分析完畢。找出質數,然后分類處理即可。線性篩處理之

其他

首先看到題:哇,1e81e81e8的范圍,這怎么做。這算法都給限制到O(n)O(n)O(n)了,難不成是有什么公式?

思考一會之后:(其實已經得到正解)用線性篩試一波,自己調試1.5秒,完蛋

嘗試各種卡常之后:優化到1.1秒了,實在頂不住了,要不直接交?

交上去之后:臥槽,MLE,那我不求MSTMSTMST前綴和了吧,直接算,但是這樣更容易超時了,糾結

再交:居然700多ms過了,杭電評測機強啊

打完比賽后,才發現,原來數據規??村e了,是1e71e71e7,根本不需要卡()

代碼

#include <bits/stdc++.h> #define fors(i, a, b) for(int i = (a); i <= (b); ++i) #define lson k<<1 #define rson k<<1|1 #define pb push_back #define lowbit(x) ((x)&(-(x))) #define mem(a) memset(a, 0, sizeof(a)) #define DDLC_ESCAPE_PLAN_FAILED ios::sync_with_stdio(false), cin.tie(0) #define int long long const int inf = 0x3f3f3f3f; const double dinf = 1e100; typedef long long ll; //const ll linf = 9223372036854775807LL; // const ll linf = 1e18; using namespace std; const int maxn = 1e7 + 10; // 比賽的時候看成1e8,導致多了一次MLE bool p[maxn]; int pr[maxn]; int pre[maxn]; void Prime(){int cnt = 0;mem(p);p[0] = p[1] = 1;for(int i = 2; i < maxn; ++i){if(!p[i]) pr[cnt++] = i;for(int j = 0; j < cnt && pr[j] * i < maxn; ++j){p[pr[j] * i] = 1;if(i % pr[j] == 0) break;}}pre[0] = pre[1] = pre[2] = 0;for(int i = 3; i < maxn; ++i){if(!p[i]) pre[i] = pre[i - 1] + 2 * i;else pre[i] = pre[i - 1] + i;} } signed main() {DDLC_ESCAPE_PLAN_FAILED;int t;cin >> t;Prime();while(t--){int n;cin >> n;cout << pre[n] << endl;}return 0; }

HDU6958 KD-Graph

看到過題數不多以及題面比較奇怪就沒做了,以后一定不能盲目看榜,以及耐心讀懂題

題意

有一個nnnmmm邊的圖(n≤100000n\leq100000n100000, m≤500000m\leq500000m500000),你需要將其分割成恰好KKK組,滿足:

  • 每組中任取兩個點p,qp,qp,q,他們之間的路徑中,最長邊不大于DDD
  • 不同組中任取兩個點p,qp,qp,q,他們之間的路徑中,所有邊都大于DDD
  • 現在給定圖和KKK,問你是否找得到一個滿足條件的DDD,如果找得到,輸出最小的DDD. 否則輸出?1-1?1.

    分析

    容易知道,相同權值的邊要么不在任何組內部,要么全都在同一組點里面。假如相同權值的邊,有的在組內,有的在組外的話,這個DDD值肯定只會更大不會更小。

    那么貪心思路顯而易見了,將所有邊按權值升序排序,使用并查集,從左往右,將所有權值相同的邊的點合并。然后統計并查集數量,更新答案。也就是在保證“相同權值的邊要么不在任何組內部,要么全都在同一組點里面”這個性質的前提下尋找能否分為KKK組。而要使DDD盡可能小,應讓處于組內的邊盡可能小,所以使用升序。

    代碼

    #include <bits/stdc++.h> #define fors(i, a, b) for(int i = (a); i <= (b); ++i) #define lson k<<1 #define rson k<<1|1 #define pb push_back #define pii pair<int, int> #define lowbit(x) ((x)&(-(x))) #define mem(a) memset(a, 0, sizeof(a)) #define DDLC_ESCAPE_PLAN_FAILED ios::sync_with_stdio(false), cin.tie(0) // #define int long long const int inf = 0x3f3f3f3f; const double dinf = 1e100; typedef long long ll; //const ll linf = 9223372036854775807LL; // const ll linf = 1e18; using namespace std; const int maxn= 100000 + 5; int fa[maxn]; struct edge{int l, r, val;bool operator < (const edge& b)const{return val < b.val;} }; vector<edge> e; inline int find(int x) {if(fa[x] == x) return x;return fa[x] = find(fa[x]); } bool join(int x, int y) {int ans = 0;int fx = find(x), fy = find(y);if(fx == fy) return 0;fa[fy] = fx;return 1; } signed main() {DDLC_ESCAPE_PLAN_FAILED;int t;cin >> t;while(t--){e.clear();int n, m, k;cin >> n >> m >> k;fors(i, 1, n) fa[i] = i;int u, v, c;fors(i, 1, m){cin >> u >> v >> c;e.pb({u, v, c});}sort(e.begin(), e.end());int now = n; // 并查集數量,初始為nbool flag = 0;int ans = 0;for(int i = 0; i < m; ++i){if(i == 0 || e[i].val != e[i - 1].val){if(now == k) break;}if(!join(e[i].l, e[i].r)) continue;now--;ans = e[i].val;}cout << (now == k ? ans : -1) << endl;}return 0; }

    HDU6957 Maximal submatrix

    題意

    給出一個矩陣,要你找一個最大的子矩陣,要求這個子矩陣每一列從上往下都是單調不下降序列。輸出最大子矩陣的面積

    分析

    懸線法,將每個不比上面的元素小的元素標記,然后用這些標記過的元素組成子矩陣。接下來使用懸線dp即可。需要注意的是,子矩陣的最上面一行是可以不被標記的。

    代碼

    (比賽時自己凹的二維dp一直超時,應該是復雜度超過O(n2)O(n^2)O(n2)了)

    第一次接觸到懸線法,代碼可能相對繁瑣

    #include <bits/stdc++.h> #define fors(i, a, b) for(int i = (a); i <= (b); ++i) #define lson k<<1 #define rson k<<1|1 #define pb push_back #define lowbit(x) ((x)&(-(x))) #define mem(a) memset(a, 0, sizeof(a)) #define DDLC_ESCAPE_PLAN_FAILED ios::sync_with_stdio(false), cin.tie(0) // #define int long long const int inf = 0x3f3f3f3f; const double dinf = 1e100; typedef long long ll; //const ll linf = 9223372036854775807LL; // const ll linf = 1e18; using namespace std; const int maxn = 2005; bool v[maxn][maxn]; int l[maxn][maxn]; int r[maxn][maxn]; int u[maxn][maxn]; signed main() {DDLC_ESCAPE_PLAN_FAILED;int t;cin >> t;while(t--){mem(v), mem(l), mem(r), mem(u);int n, m;cin >> n >> m;fors(i, 1, n){fors(j, 1, m){cin >> u[i][j];l[i][j] = j;r[i][j] = j;}}fors(i, 1, n){fors(j, 1, m){if(i == 1 || u[i][j] >= u[i - 1][j]){v[i][j] = 1;}}}fors(i, 1, n){fors(j, 2, m){if(v[i][j] && v[i][j - 1]) l[i][j] = l[i][j - 1];}for(int j = m - 1; j >= 1; --j){if(v[i][j] && v[i][j + 1]) r[i][j] = r[i][j + 1];}}mem(u);fors(i, 1, n){fors(j, 1, m) u[i][j] = 1;}int ans = 0;fors(i, 1, n){fors(j, 1, m){if(v[i][j] && v[i - 1][j]){l[i][j] = max(l[i - 1][j], l[i][j]);}if(v[i][j]) u[i][j] = u[i - 1][j] + 1;}for(int j = m; j >= 1; --j){if(v[i][j] && v[i - 1][j]){r[i][j] = min(r[i - 1][j], r[i][j]);}}}fors(i, 1, n){fors(j, 1, m){ans = max(ans, u[i][j] * (r[i][j] - l[i][j] + 1));}}cout << ans << endl;}return 0; }

    HDU6955 Xor sum

    題意

    給一個整數數組,你需要找到最短的區間,其按位異或和不小于kkk. 如果有多個,找出左端點最左的

    分析

    先轉化一下。異或運算里,任意xxx的逆元是xxx本身,故對于前綴和pre[i]pre[i]pre[i],pre[j]pre[j]pre[j]iiijjj的異或和可以表示為pre[i]pre[i]pre[i]^pre[j]pre[j]pre[j].

    這之后,直接存異或和,問題轉化為:找到兩個相距最近的i,ji,ji,j,其異或和不小于kkk.

    枚舉右端點,然后可能的左端點用TrieTrieTrie樹維護,從左到右找,每次找到一個可能的編號就覆蓋一下,這樣能保證最后找到的是最右邊的。不過也可以直接保存最右邊的節點。

    以后千萬不要看著std調試代碼,調著調著就調得跟std一模一樣了

    不過說白了也是之前從來沒用過trie吧orz,根本不熟

    代碼

    /*** @file :vsDebug.cpp* @brief :* @date :2021-07-21* @Motto :Love Sakurai Yamauchi Forever*/ #include <bits/stdc++.h> #define fors(i, a, b) for(int i = (a); i <= (b); ++i) #define lson k<<1 #define rson k<<1|1 #define pb push_back #define lowbit(x) ((x)&(-(x))) #define mem(a) memset(a, 0, sizeof(a)) #define DDLC_ESCAPE_PLAN_FAILED ios::sync_with_stdio(false), cin.tie(0) // #define int long long const int inf = 0x3f3f3f3f; const double dinf = 1e100; typedef long long ll; //const ll linf = 9223372036854775807LL; // const ll linf = 1e18; using namespace std; const int maxn = 1e5 + 10; const int mnx = (1LL << 24) + 10; int p[mnx][2], res[mnx], a[maxn]; signed main() {DDLC_ESCAPE_PLAN_FAILED;int t;cin >> t;while(t--){int n, k;cin >> n >> k;fors(i, 1, n){cin >> a[i];a[i] ^= a[i - 1]; // 只存前綴和}int l = -1, r = n, ans = 1;res[1] = -1;p[1][0] = p[1][1] = 0; // initfors(i, 0, n){int x = 1;int tmp = -1;for(int j = 29; j >= 0; --j){if(!x) break;int u = (a[i] >> j) & 1; // 從上往下第j位if(!((k >> j) & 1)){if(p[x][u ^ 1]){tmp = max(tmp, res[p[x][u ^ 1]]);}x = p[x][u];}else x = p[x][u ^ 1];}if(x) tmp = max(tmp, res[x]);if(tmp >= 0 && i - tmp < r - l) l = tmp, r = i;x = 1;for(int j = 29; j >= 0; --j){int u = (a[i] >> j) & 1;if(!p[x][u]){ans++;p[x][u] = ans, res[ans] = -1;p[ans][0] = p[ans][1] = 0;}x = p[x][u];res[x] = max(res[x], i);}}if(l >= 0) cout << l + 1 << ' ' << r << endl;else cout << -1 << endl;}return 0; }

    總結

    以上是生活随笔為你收集整理的2021“MINIEYE杯”中国大学生算法设计超级联赛(1)个人解题报告的全部內容,希望文章能夠幫你解決所遇到的問題。

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