Codeforces Global Round 1 (A-E題解)
Codeforces Global Round 1
題目鏈接:https://codeforces.com/contest/1110
A. Parity
題意:
給出{ak},b,k,判斷a1*b^(k-1)+a2*b^(k-2)+...+ak*b^0的奇偶性。
題解:
暴力求模2意義下的值就好了。
代碼如下:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 2e5+5; int n; int b,k; int a[N]; ll qp(ll A,ll B){ ll ansView Code= 1; while(B){ if(B&1) ans=ans*A%2; A=A*A%2; B>>=1; } return ans; } int main(){ cin>>b>>k; for(int i=1;i<=k;i++) scanf("%d",&a[i]); int t=b%2; int sum = 0; for(int i=k-1;i>=0;i--){ sum=sum+a[k-i]*qp(t,i); sum%=2; } if(sum&1) cout<<"odd"; else cout<<"even"; return 0; }
B. Tape
題意:
在[1,m]這個區間中,有n個點,現在要用k個木棍去覆蓋完這些點,問最短覆蓋長度為多少。
題解:
首先將起始點和終點間的距離求出來,然後考慮將不需要的一些覆蓋給減去。
具體做法就是用優先隊列保存兩個相鄰點之間的間隔,然後不斷取最大的間隔減去,最後使得剩下的區間還剩下k個即可。
代碼如下:
#include <bits/stdc++.h> #defineView CodeINF 0x3f3f3f3f using namespace std; typedef long long ll; const int N = 1e5+5; int n,m,k; ll a[N],d[N]; ll ans; int main(){ scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=n;i++) scanf("%I64d",&a[i]); ans=a[n]-a[1]+1; priority_queue <ll> q; for(int i=1;i<n;i++){ d[i]=a[i+1]-a[i]; q.push(d[i]-1); } int cnt = 1; while(cnt<k){ ll now = q.top();q.pop(); cnt++; ans-=now; } cout<<ans; return 0; }
C. Meaningless Operations
題意:
有多個詢問,每次詢問會輸入一個數a,然後對於所有的數b(1<=b<a),求max{ gcd(a&b,a^b) }。
題解:
這個可以打表來做。
如果想的話,就是分兩種情況考慮:一種是所有二進制位數都為1,另一種就是並非這樣。
第二種思考起來比較簡單,答案肯定為2^x-1,我們取的b只需要剛好把a二進制中的0填補就行了。
第一種情況會有一個這樣的性質:a&b+a^b=a。現在設g=gcd(a&b,a^b),所以現在有g|a&b,g|a^b,那麽自然有g|a。
我們會發現g其實為a的因子,那麽這種情況找a的最大因子就好啦。
代碼如下:
#include <bits/stdc++.h> using namespace std; typedef long long ll; int q; ll a; ll p2[30]; ll Print(ll x){ for(ll i=3;i*i<=x;i++){ if(x%i==0){ return x/i; } } return 1; } int main(){ cin>>q; p2[0]=1; for(int i=1;i<=26;i++) p2[i]=p2[i-1]*2; while(q--){ cin>>a; int i; for(i=26;i>=0;i--) if((1<<i)&a) break ; if(a&(a+1)) cout<<p2[i+1]-1<<endl; else cout<<Print(a)<<endl; } return 0; }View Code
D. Jongmah
題意:
給出n個數,數的大小不超過m,問最多有多少個類似於(x,x,x),(x-1,x,x+1)這樣的三元組,每個數最多用一次。
題解:
對於我這樣的蒟蒻來說,dp方程式理解了很久,感覺十分巧妙。
首先,就是對於類似於(x-1,x,x+1)這樣的三元組來說,我們只需要考慮不超過三個的情況就可以了。因為當其超過三個時,直接選(x,x,x)這種類型得到的答案是一樣的。
設dp(i,j,k)的定義為:當前在i這個位置,有j個(i-1,i,i+1)三元組,有k個(i,i+1,i+2)這樣的三元組。
轉移的話就從(i-2,i-1,i),(i-1,i,i+1) (即i-1)轉移過來,我們在計算的時候附加上(x,x,x)這種類型就好了。
因為每次都從i-1轉移過來,所以還可以用滾動數組優化掉一維,但是不優化對於這題也沒啥影響~
代碼如下:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1e6+5; int n,m; int a[N],dp[N][3][3]; int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ int x; scanf("%d",&x); a[x]++; } for(int i=1;i<=m;i++){ for(int j=0;j<3;j++){ for(int k=0;k<3;k++){ for(int l=0;l<3;l++){ if(l+j+k>a[i]) continue ; dp[i][k][l]=max(dp[i][k][l],dp[i-1][j][k]+l+(a[i]-l-k-j)/3); } } } } cout<<dp[m][0][0]; return 0; }View Code
E. Magic Stones
題意:
給出兩個數列{cn},{tn},現在可以進行一些變化,比如對於ci來說,可以讓ci=ci-1+ci+1-ci (2<=i<n),變化的次數以及位置不限,問是否最後能得到t數列。
題解:
這題也比較巧妙吧,首先判斷一下首尾可以知道是否可行。
之後根據這個式子,利用差分數組來解。
設di=ci+1-ci,那麽當ci變化後,di=ci‘-ci-1=ci+1-ci=di+1,di+1=di,也就是說,兩個差分數組相當於換了下位置。
也就是說,題目中的操作,實質上是不斷交換差分數組的位置。
之後就有很多種方法了,給出我的代碼吧:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1e5+5; int n; ll c[N],t[N],d[N]; multiset <ll> s; int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&c[i]); for(int i=1;i<=n;i++) scanf("%d",&t[i]); if(c[1]!=t[1] || c[n]!=t[n]){ cout<<"No"; return 0; } for(int i=1;i<n;i++) d[i]=c[i+1]-c[i],s.insert(d[i]); for(int i=2;i<=n;i++){ ll need = t[i]-t[i-1]; auto it = s.lower_bound(need); if(*it==need){ s.erase(it); }else{ cout<<"No"; return 0; } } cout<<"Yes"; return 0; }View Code
除開這種,還可以求出t數列的差分數組,然後對兩個差分數組進行排序來比較,實現方法比我簡單多了。
Codeforces Global Round 1 (A-E題解)