ACM2023SWJTU寒假选拔赛2不完全题解
- 2022.01.15.更新D | L:數學找規律 | dfs(tle)->貪心模擬
- 2022.01.14.更新L題:統計連通子圖數模型,三解:dsu,bfs,dfs
文章目錄
- B - 這是一道方塊題 [CodeForces 272C](https://vjudge.net/problem/CodeForces-272C/origin)
- [E - 這是一道果果題](https://vjudge.net/problem/CodeForces-743B)[CodeForces - 743B ](https://vjudge.net/problem/CodeForces-743B/origin)
- [G - 這是一道樹林題](https://vjudge.net/problem/POJ-3090)[POJ - 3090](https://vjudge.net/problem/POJ-3090/origin)
- [J - 這是一道貓咪題](https://vjudge.net/problem/CodeForces-1070D)[CodeForces - 1070D ](https://vjudge.net/problem/CodeForces-1070D/origin)
- [L - 這是一道玩具題](https://vjudge.net/problem/CodeForces-1209D) [CodeForces - 1209D](https://vjudge.net/problem/CodeForces-1209D/origin)
- [D - 這是一道算數題](https://vjudge.net/problem/Gym-104090D)[Gym - 104090D ](https://vjudge.net/problem/Gym-104090D/origin)
- [K - 這是一道奶茶題](https://vjudge.net/problem/CodeForces-863B) [CodeForces - 863B ](https://vjudge.net/problem/CodeForces-863B/origin)
B - 這是一道方塊題 CodeForces 272C
線段樹模版題
Description
一天,公孫晚霽正在玩這款新型的俄羅斯方塊游戲,游戲中一共有$ n $列空間,她將方塊排列成了從左到右下方填滿,依次增高的階梯形狀 第一列的高度為 a 1 a_1 a1?,第二列的高度為 a 2 a_2 a2?,…,第 n列的高度為 $ a_n (1≤a1≤a2≤…≤an)。$
這時,公孫英朗來給公孫晚霽搗亂了,他搶過了游戲手柄,將接下來的 mm 塊方塊都移動到最左側,依次下落,第 i塊方塊的寬為 w i w_i wi?,高為 h i h_i hi?。請幫公孫晚霽計算一下,每塊方塊下落后,方塊下邊緣距離游戲場景底部的距離。
如圖
Input
- 列數n
- 每列高度 a 1 , a 1 , . . . , a n {a1,a1,...,an} a1,a1,...,an
- 新方塊數m
- 每個方塊尺寸 w , h w,h w,h
Output
一共輸出 mm 行,每行一個整數,表示方塊落下后,下邊緣距離游戲場景底部的距離。
Solution
線段樹板子,每個方塊下落時,落在區間最值 m a x n ( 1 : w ) maxn(1:w) maxn(1:w)位置,這個區間被賦新值 a ( 1 : w ) = m a x n + h a(1:w)=maxn+h a(1:w)=maxn+h
Code
#include<bits/stdc++.h> using namespace std; using ll=long long;const int N=1e5+5;ll a[N]; ll d[N<<2]={0}; ll tag[N<<2]={0};inline int left(int i) { return i<<1; } inline int right(int i) { return i<<1|1; } inline int fa(int i) { return i>>1; }inline void push_up(int p) { //線段樹維護區間最值d[p] = max(d[left(p)] , d[right(p)] ); } inline void push_down(int l,int r,int p) {if (!tag[p]) return;int mid = (l + r) >> 1;tag[left(p)] = tag[p];tag[right(p)] = tag[p];d[left(p)] = tag[p];d[right(p)] = tag[p];tag[p] = 0; }void build(int l,int r,int p) {if(l==r) {d[p]=a[l];return; }int mid=(l+r)>>1;build(l,mid,left(p));build(mid+1,r,right(p));push_up(p); } ll query(int lo,int hi,int l,int r,int p) {ll res=0;if(lo<=l && r<=hi) return d[p];int mid=(l+r)>>1;push_down(l,r,p);if(lo<=mid) res=max(res,query(lo,hi,l,mid,left(p)));if(hi>mid) res=max(res,query(lo,hi,mid+1,r,right(p)));return res; } void update(int lo,int hi,int l,int r,int p,ll elm) {//區間修改操作位區間賦值if(lo<=l && r<=hi){d[p]=elm;tag[p]=elm;return;}push_down(l,r,p);int mid = (l + r) >> 1;if (lo <= mid) update(lo, hi, l , mid, left(p),elm);if (hi > mid ) update(lo, hi, mid+1, r , right(p),elm);push_up(p); } int main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int n;cin>>n;for(int i=1;i<=n;i++){cin>>a[i];}build(1,n,1); // for(int i=1,lvl=0;i<=4*n;lvl++) {for(int j=1;j<=1<<lvl;j++) cout<<d[i++]<<" "; cout<<'\n';}int m;cin>>m;while(m--){int w,h;cin>>w>>h;ll maxn=query(1,w,1,n,1);cout<<maxn<<'\n';update(1,w,1,n,1,maxn+h);}return 0;}E - 這是一道果果題CodeForces - 743B
找規律
Description
公孫英朗給公孫晚霽買了很多果果,公孫晚霽很喜歡,但是為了她的減肥計劃,她一天不能吃太多果果。
公孫晚霽的減肥計劃由n步生成,生成過程如下:
- 第一步規定第1天只能吃一個果果;
- 隨后每一步,將之前確定的所有計劃復制附加在末尾,并在中間插入未使用過的最小正整數。
根據這個過程,當n=1時,該計劃進行一天,這天可以吃的果果數量為1。
當n=2時,該計劃進行三天,這些天可以吃的果果數量為[1,2,1]。
當n=3時,該計劃進行七天,這些天可以吃的果果數量為[1,2,1,3,1,2,1].請你幫公孫晚霽計算一下,依照該計劃,第k天她能吃多少果果。
Input
1 ≤ n ≤ 50 , 1 ≤ k ≤ 2 50 ? 1 1\le n \le 50,1\le k \le 2^{50} -1 1≤n≤50,1≤k≤250?1
Solution
這個序列為, { 1 1 , 2 2 , 1 3 , 3 4 , 1 5 , 2 6 , 1 7 , 4 8 , 1 9 , 2 10 , 1 11 , 3 12 , 1 13 , 2 14 , 1 15 , 5 16 , 1 , 2 , 1 , 3 , 1 , 2 , 1 , 4 , 1 , 2 , 1 , 3 , 1 , 2 , 1 , . . . } \{1_1,2_2,1_3,3_4,1_5,2_6,1_7,4_8,1_9,2_{10},1_{11},3_{12},1_{13},2_{14},1_{15},5_{16},1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,...\} {11?,22?,13?,34?,15?,26?,17?,48?,19?,210?,111?,312?,113?,214?,115?,516?,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,...}
可以觀察出一些性質
- 第 2 i 2^i 2i個元素,其值為 i + 1 i+1 i+1
- 第 K K K個元素,由**“復制”**的特性,其值等于第 K ? ( 1 < < l g ( K ) ) K-(1<<lg(K)) K?(1<<lg(K))個元素
tle遞推式子
ll query(ll k) { ll bin=0;while( ( 1<<bin ) <= k) bin++; bin--;if(k==1<<bin) return bin+1;else return query(k-(1<<bin));這個bin是難求而重復的,tle了,如果通過map記憶化遞歸推lg,mle了
繼續觀察這個序列 1 , 2 , 1 , 3 , 1 , 2 , 1 , 4 , 1 , 2 , 1 , 3 , 1 , 2 , 1 {1,2,1,3,1,2,1,4,1,2,1,3,1,2,1} 1,2,1,3,1,2,1,4,1,2,1,3,1,2,1
1: 1 3 5 7 9 ,... beg=2^0,del=2^1 2: 2 6 10 ,... beg=2^1,del=2^2 3: 4 12 20 ,... beg=2^2,del=2^3 4: 8 ,... beg=2^3,del=2^4根據這個來求就好了:減去beg,判是否整除del
Code
ll querr(ll n,ll k) {for(ll i=1;i<=n+1;i++){ll tmp=k-(1ll*1<<(i-1));if(tmp%(1ll*1<<(i))==0) {return i;}} }G - 這是一道樹林題POJ - 3090
歐拉篩模版題
學校里的小樹林種成了一個 ( n + 1 ) ? ( n + 1 ) (n+1) * (n+1) (n+1)?(n+1) 大小的密密麻麻的正方形矩陣,公孫英朗和公孫晚霽在樹林里捉迷藏。
公孫英朗面朝樹干,公孫晚霽躲了起來。3…2…1… 隨后公孫英朗轉頭,開始捉公孫晚霽啦~
公孫英朗從 (0, 0) 的位置轉頭,公孫晚霽就藏在了這些樹后邊,因為樹之間有遮擋關系,公孫英朗只能看見一部分樹,請幫公孫晚霽計算一下,公孫英朗能看見多少樹。
小樹林中每一顆樹都看做平面直角坐標系下的一個個點,從 (0, 0) 到 (n, n)都種滿了樹。當 n=5時,小樹林的樣子如下圖所示:
當某點與 (0, 0的連線上有其它點時,該點會被連線上的點遮擋,公孫英朗就看不見這棵樹了,如 (4, 2)這棵樹會被 (2, 1)這棵樹擋住,公孫英朗看不見位于 (4, 2) 的這課樹。
Input
樣例數T 1 ≤ T ≤ 1 e 3 1 \le T \le 1e3 1≤T≤1e3
矩陣規模n 1 ≤ n ≤ 1 e 3 1 \le n \le 1e3 1≤n≤1e3
Output
看見的樹木cnt
Solution
對于起點為原點的射線,可由斜率唯一確定。
用map記錄每一對 ( i , j ) (i,j) (i,j)的斜率,打表也能過,不優化是 O ( T n n l o g n ) O(Tnnlogn) O(Tnnlogn),T了
正解是歐拉函數板子。
歐 拉 函 數 : 小 于 等 于 n 的 與 n 互 質 的 正 整 數 的 個 數 歐拉函數:小于等于n的與n互質的正整數的個數 歐拉函數:小于等于n的與n互質的正整數的個數
φ ( n ) = { n ? 1 , n 為 質 數 j ? φ [ i ] , i j = n , i % j = = 0 ( j ? 1 ) ? φ [ i ] , i j = n \varphi(n)= \begin{cases} n-1&,n為質數\\ j * \varphi[i]&,ij=n,i\%j==0\\ (j-1) *\varphi[i]&,ij=n\\ \end{cases} φ(n)=??????n?1j?φ[i](j?1)?φ[i]?,n為質數,ij=n,i%j==0,ij=n?
矩陣左上角與右下角是對稱的,考慮一半就好.
考查右下角三角形內任意數對 ( x , y ) ( 1 ≤ x ≤ y ) (x,y)(1\le x \le y) (x,y)(1≤x≤y)
其唯一確定斜率 k = y x k=\frac{y}{x} k=xy?,當 g c d ( x , y ) ! = 1 gcd(x,y)!=1 gcd(x,y)!=1時,這個斜率可由其左下角某個數對表示(成比例)
反之,當 g c d ( x , y ) = = 1 gcd(x,y)==1 gcd(x,y)==1時,即k不可再約,這個元素不重復
暨,給定 x = C x=C x=C,任取 1 ≤ y ≤ n 1\le y\le n 1≤y≤n,不重復的斜率 k = y x k=\frac{y}{x} k=xy?滿足xy互質,這正是歐拉函數的定義
∴ a n s = 3 + 2 ? ∑ 2 n p h i [ i ] ans=3+2*\sum_2^n phi[i] ans=3+2?∑2n?phi[i]
Code
void phis() {phi[1]=1;for(int i=2;i<=N;i++){if(!vis[i]){prime[cnt++]=i;phi[i]=i-1;}for(int j=0;j<cnt && i*prime[j]<=N;j++){vis[prime[j]*i]=1;if(i%prime[j]==0){phi[i*prime[j]]=prime[j] * phi[i];break;}else phi[i*prime[j]]=(prime[j] -1 ) *phi[i]; }} } void solve(int n) {ll ans=0;for(int i=2;i<=n;i++) ans+=phi[i];ans=ans*2+3;cout<<ans<<"\n"; }int main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);phis();int T;cin>>T;for(int i=1;i<=T;i++){int n;cin>>n;cout<<i<<" "<<n<<" ";solve(n);}return 0;}J - 這是一道貓咪題CodeForces - 1070D
小模擬
Description
公孫晚霽領養了一只學校里的流浪貓咪,并將給貓咪剪指甲這個工作交給了公孫英朗,讓貓咪做公孫英朗的貓主子。
假設貓咪指甲的正常長度為一確定值,且當貓咪的指甲長度比正常長度長出長度為 k k k 時,可能會傷到別人,因此當貓咪的指甲達到$ 正常長度 +k$ 時就必須進行一次修剪。貓咪的指甲長得很快,一個月之內可能進行多次修剪。為了保護貓咪,指甲不能被剪到正常長度以下,且晚霽認為貓咪當月長出的指甲必須在當月或下個月被剪掉。
已知貓咪當前的指甲長度為正常長度,接下來的 n n n個月中的第 i i i個月,貓咪指甲會增長的長度為$ a_i 。 ? ? 公 孫 英 朗 想 要 讓 個 月 結 。**公孫英朗想要讓個月結 。??公孫英朗想要讓個月結 n $束后,貓咪的指甲仍然為正常長度**。請計算公孫英朗最少需要修剪貓咪指甲的次數cnt。
正常長度=0
Input
第一行包含兩個整數 n和k ( 1 ≤ n ≤ 2 ? 1 0 5 , 1 ≤ k ≤ 1 0 9 (1 \le n \le 2\cdot10^5, 1 \le k \le 10^9 (1≤n≤2?105,1≤k≤109,表示月份的數量和指甲可以超出正常長度的最長長度。
第二行包含 nn 個整數 a_i ( 0 ≤ a i ≤ 1 0 9 ) (0 \le a_i \le 10^9) (0≤ai?≤109),表示第 i個月貓咪指甲的增長長度
注:當貓爪長度逾k后,需立即修剪。
Solution
模擬
Code
#include<bits/stdc++.h> using namespace std; using ll=long long;const int N=1e5+5;int vis[N]={0}; int main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int n,m;cin>>n>>m;int cnt=0; for(int i=1;i<=m;i++){int x,y;cin>>x>>y;if(vis[x] && vis[y]){cout<<i<<' ';cnt++;}vis[x]=1;vis[y]=1;}cout<<cnt;return 0;}L - 這是一道玩具題 CodeForces - 1209D
圖論連通分量建模
Description
公孫晚霽和公孫英朗打算去孤兒院做志愿活動。第一次去之前,公孫晚霽準備了 nn 種玩具各一個,送給 mm 小朋友們玩。在這 nn 種玩具中,每個小朋友都有2種喜歡的玩具。分玩具的步驟為:
- 首先,小朋友將按照公孫英朗的要求進行排隊。
- 然后小朋友按照排隊順序逐一獲取玩具。
- 每個小朋友會拿走他/她喜歡的所有玩具。
- 沒有拿到玩具的小朋友將會很傷心,拿到玩具的小朋友將會很開心。
已知每個小朋友喜歡的玩具的種類。請幫公孫英朗計算傷心的小朋友最少有幾個?
Input
玩具個數n,小朋友個數m
每個小朋友喜歡的玩具 x i , y i xi,yi xi,yi
Output
傷心的小朋友個數cnt
Solution
圖論建模,將玩具建模為點,將小朋友建模為兩點之間的邊。對于一張有n個點的連通圖,可以證明地是最多同時滿足n-1個小朋友,即,策略是,按拓撲序加入n-1條邊,所形成的最小生成樹。此后所有點被鏈接,新邊無法加入(sad people)
而題面所述的圖可能是不連通的,求其連通分量數目即可。有bfs,dfs,dsu三種解法
A N S = M ? ( n ? c o u n t ( ) ) ANS=M-(n-count()) ANS=M?(n?count())
Code
- dsu 62 ms,3900 KB
邊集數組存圖,用并查集來維護連通分量:將連通的點放在同一個集合(共祖先)里,統計dsu映射中祖先的個數即可知集合的個數
#include<bits/stdc++.h> using namespace std; using ll=long long;// 連通分量問題:將玩具建模為點,將child建模為兩點之間的邊:每入一條邊,其兩端的點被vis。 //在一張n個點(玩具)m條邊(child)的連通圖中,通過適當的(拓撲序)讀邊,可以滿足N-1個child。(生成樹) //考查本題所建模的圖,可以是不連通而有若干連通分量的,用并查集來維護連通分量數。 const int N=1e5+5,M=2*N; struct Edge{int from,to; }edge[M]; int cnt_e=0; void add(int u,int v) {edge[++cnt_e].from=u;edge[cnt_e].to=v; } int n,m; //dsu int dsu[N]={0}; int find(int x) { return dsu[x]==x?x:dsu[x]=find(dsu[x]);} void unite(int lhs,int rhs) {dsu[find(rhs)]=find(lhs); }int vis[N]; int count() {int cnt=0;for(int i=1;i<=n;i++){if(!vis[find(i)]){vis[find(i)]=1;cnt++;}}return cnt; } int main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cin>>n>>m;for(int i=1;i<=n;i++) dsu[i]=i;for(int i=1;i<=m;i++){int u,v;cin>>u>>v;add(u,v);add(v,u);unite(u,v);}cout<<max(0,m-(n-count()));return 0;}bfs 78 ms 2600 KB
鏈式前向星存圖,每次bfs為訪問過的邊打上
#include<bits/stdc++.h> using namespace std; using ll=long long;// 連通分量問題:將玩具建模為點,將child建模為兩點之間的邊:每入一條邊,其兩端的點被vis。 //在一張n個點(玩具)m條邊(child)的連通圖中,通過適當的(拓撲序)讀邊,可以滿足N-1個child。(生成樹) //考查本題所建模的圖,可以是不連通而有若干連通分量的,用并查集來維護連通分量數。 const int N=1e5+5,M=2*N; struct Edge{int to, nxt; }edge[M]; int cnt_e=0; int head[N]={0}; void add(int u,int v) {edge[++cnt_e].to=v;edge[cnt_e].nxt=head[u];head[u]=cnt_e; } int n,m; bool vis[N]={0}; int cnt=0; void bfs(int beg) {if(!vis[beg]) cnt++;queue<int> que;que.push(beg);while(!que.empty()){int u=que.front();que.pop();if(!vis[u]){vis[u]=1;for(int j=head[u];j;j=edge[j].nxt){int to=edge[j].to;if(!vis[to]){que.push(to);}}}} } int main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cin>>n>>m;for(int i=1;i<=m;i++){int u,v;cin>>u>>v;add(u,v);add(v,u);}for(int i=1;i<=n;i++) bfs(i);cout<<max(0,m-(n-cnt));return 0;}dfs 同上 鏈式前向星存圖 62 ms 5200 KB
void dfs(int u) {if(vis[u]) return;vis[u]=1;for(int j=head[u];j;j=edge[j].nxt){int to=edge[j].to;if(!vis[to]) dfs(to);} } for(int i=1;i<=n;i++) {if(!vis[i]){cnt++;dfs(i);} }效率比較
D - 這是一道算數題Gym - 104090D
awesome找規律
Description
公孫英朗的算數技能太差了,公孫晚霽決定給公孫英朗進行算數訓練。
公孫晚霽準備了nn個整數,公孫英朗需要按順序完成以下操作:
- 將第i個數減去一半,并將減掉的部分加到第i+1個數上;
- 將第 n 個數減去一半,并將減掉的部分加到第1個數上;
為了讓公孫英朗表達對自己的愛意,公孫晚霽決定讓他執行以上訓練過程 520131 4 33441573 5201314^{33441573} 520131433441573輪。請幫公孫英朗計算出執行后的最終結果。
Solution
**打表看看每輪結果,最終結果會固定。**而while(1)等其固定會tle
再找找規律:
K = s u m / ( n + 1 ) a 1 = 2 K , a i = K K=sum/(n+1)\\ a1=2K,ai=K K=sum/(n+1)a1=2K,ai=K
1. 在減數和搬運的過程中,sum守恒,數列的總和從未改變
2. 基于若干次操作后,數列趨于穩定的事實:
3. 對于“將第i個數的一半搬運給第i+1個數”這個回圈的操作,2:1:1:1:1...這個比例滿足穩定的需求。
∴ 將sum分為n+1份,a1占兩份,其余占一份
Code
#include<bits/stdc++.h> using namespace std; using ll=long long;const int N=1e5+5; int n; double a[N]; int main() { // ios::sync_with_stdio(false); // cin.tie(0);cout.tie(0);double sum=0;cin>>n;for(int i=1;i<=n;i++){cin>>a[i];sum+=a[i];}double k=sum/(n+1);printf("%f ",2*k);for(int i=2;i<=n;i++) printf("%f ",k); // puts(""); // double last=-1; // while(1) // { // // for(int i=1;i<n;i++) // { // a[i]/=2; // a[i+1]+=a[i]; // } // a[n]/=2; // a[1]+=a[n]; // if(last==a[1]) // { // for(int i=1;i<=n;i++)printf("%f ",a[i]); // return 0; // } // last=a[1]; // // }return 0;}K - 這是一道奶茶題 CodeForces - 863B
Description
公孫英朗打算請大家喝奶茶,于是他和公孫晚霽兩人到奶茶店,下單了 2 n 2n 2n 杯不同的飲品。
由于購買了偶數杯,公孫晚霽本打算全部使用兩杯裝一起的方式打包帶到 T 6023 T6023 T6023。但不幸的是,奶茶店僅剩了 n ? 1 n-1 n?1 個兩杯裝袋子和若干一杯裝袋子。于是公孫晚霽不得己決定使用全部的兩杯裝包裝,再使用2個一杯裝包裝進行打包。
當使用兩杯裝包裝時,公孫晚霽發現因為每杯重量不同,這些包裝會產生不平衡值,若這兩杯的重量分別為 u u u和 v v v,則不平衡值為$ abs(u-v)$。一杯裝包裝不產生不平衡值。
拎著奶茶的公孫英朗想讓不平衡值的和盡可能小,請你求出該最小值。
Input
n , 1 ≤ n ≤ 50 n,1\le n\le 50 n,1≤n≤50
奶茶重量 { a 0 , a 1 , . . . , a 2 n } \{a0,a1,...,a2n\} {a0,a1,...,a2n}
Output
ans
人話
一個序列,選擇兩個數去掉,其他的自由組合,使總差和最小
Solution
貪心地認為,同一個袋子里的兩杯奶茶重量應該接近
即,若先對數組排序,然后分組,同組兩杯奶茶是相鄰的。
即,從序列 1 , 2 , 3 , 4 , . . , 2 n {1,2,3,4,..,2n} 1,2,3,4,..,2n中有 2 n ? 1 2n-1 2n?1對相鄰元素,選取作差最小的前 n ? 1 n-1 n?1對相鄰元素即可
基此可以圖論爆搜:建邊集數組,邊 [ i : ? > i : 1 ] . v a l = a [ i + 1 ] ? a [ i ] [i:->i:1].val=a[i+1]-a[i] [i:?>i:1].val=a[i+1]?a[i]然后按邊權排序,然后dfs搜 n ? 1 n-1 n?1層,每層搜一條弧頭弧尾未vis的邊
Code
DFS θ ( 2 n ) n ? 1 \theta(2n)^{n-1} θ(2n)n?1,TLE
#include<bits/stdc++.h> using namespace std; using ll=long long;const int N=55; int n; int a[2*N];struct Edge{int from,to,val; }edge[2*N]; int cnt_e=0; void add(int u,int v,int val) {edge[cnt_e].from=u;edge[cnt_e].to=v;edge[cnt_e++].val=val; } bool cmp(const Edge& lhs,const Edge& rhs) {return lhs.val<rhs.val;}bool vis[N]={0};int ans=0x7f7f7f7f; vector<Edge> vec; void dfs(int lvl,int sum) {if(lvl>n-1){cout<<sum<<'\n';for(auto it:vec) cout<<it.from<<" "<<it.to<<" "<<it.val<<'\n'; cout<<'\n';ans=min(ans,sum);return;}for(int i=0;i<cnt_e;i++){if(!vis[edge[i].from] && !vis[edge[i].to]){vis[edge[i].from]=1;vis[edge[i].to] =1;vec.push_back(edge[i]);dfs(lvl+1,sum+edge[i].val);vis[edge[i].from]=0;vis[edge[i].to] =0;vec.pop_back();}} } int main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cin>>n;for(int i=1;i<=2*n;i++) cin>>a[i];sort(a+1,a+2*n+1);for(int i=1;i<=2*n-1;i++){add(i,i+1,a[i+1]-a[i]);}sort(edge,edge+cnt_e,cmp); dfs(1,0);cout<<ans;return 0;}枚舉
打表觀察一下選出的組合,還是前邊那句同組兩杯奶茶是相鄰的
而未選用的兩杯奶茶未必相鄰:只需滿足減去這兩個元素后,剩余序列倆倆一組依舊相鄰即可,eg, { _ , 2 , 3 , _ , 5 , 6 , . . } \{\_,2,3,\_,5,6,..\} {_,2,3,_,5,6,..}
能枚舉出所有刪點的情況即可。
刪去兩個點將原序列分為三個區間,需要這三個區間長度均為偶數,才符合依舊相鄰的規則
,eg { 1 , 2 , _ , 4 , 5 , _ , 7 , 8 } \{1,2,\_,4,5,\_,7,8\} {1,2,_,4,5,_,7,8}
刪點策略為:第一個點必為奇數,第二個點與第一個點間隔偶數距離,然后簡單讀相鄰元素差即可。
一點點思維的小模擬。
Code AC
#include<bits/stdc++.h> using namespace std; using ll=long long;int n; const int N=55; int a[2*N]; int b[2*N]; bool vis[2*N]={0}; int ans=0x7f7f7f7f;void solve() {int sum=0;for(int i=1;i<=2*n;){if(vis[i]) i++;if(vis[i]) i++;sum+=a[i+1]-a[i];i+=2;}ans=min(ans,sum); } int main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cin>>n;for(int i=1;i<=2*n;i++) cin>>a[i];sort(a+1,a+2*n+1);for(int i=1;i<=2*n;i+=2){vis[i]=1;for(int j=i+1;j<=2*n;j+=2){vis[j]=1;solve();vis[j]=0;}vis[i]=0;}cout<<ans;return 0;}總結
以上是生活随笔為你收集整理的ACM2023SWJTU寒假选拔赛2不完全题解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 夏季养生:夏季养生必备五种中药材
- 下一篇: uni-app uView UI框架 下