CF每日一練(2.11)
阿新 • • 發佈:2019-02-11
只需要 nod tor part got include ons main 連續
CF-1114
A. Got Any Grapes?
skip
B. Yet Another Array Partitioning Task
- 將n個數分成連續的k組,使得每組的前m大的數字的總和最大。
- 首先可以想到肯定可以包含n個數中前 m*k 大的數。所以可以先將他們標記,然後掃一遍確定每組的端點即可
#include <bits/stdc++.h> using namespace std; typedef long long ll; int n,m,k; struct node{ int x; int id; }a[200010]; int v[200010]; bool cmp(node a,node b){ return a.x>b.x; } int main(){ cin>>n>>m>>k; for(int i=1;i<=n;i++){ scanf("%d",&a[i].x); a[i].id = i; } sort(a+1,a+n+1,cmp); ll sum = 0; for(int i=1;i<=m*k;i++){ v[a[i].id] = 1; sum += a[i].x; } vector<int> ans; int num = 0; for(int i=1;i<=n;i++){ if(v[i])num++; if(num==m){ ans.push_back(i);num=0; if(ans.size()==k-1) break; } } cout<<sum<<endl; for(int i=0;i<k-1;i++) cout<<ans[i]<<‘ ‘; puts(""); return 0; }
C. Trailing Loves (or L‘oeufs?)
- $ n! = p_1^{x_1} \cdot p_2^{x_2}\cdots p_m^{x_m} \cdot Q$
- \(b = p_1^{y_1} \cdot p_2^{y_2} \cdots p_m^{y_m}\)
分解n!的質因數復雜度為 O(log N)。所以我們可以將b分解質因數,對於質因數\(p_i\),計算n!含有多少個質因子\(p_i\) (設\(x_i\)) ,則該質因子下答案為 \(\lfloor x_i/y_i \rfloor\) , 最終\(ans = min \{ \lfloor x_1/y_1 \rfloor \cdots \lfloor x_m/y_m\rfloor \}\)
- 計算n!中含有多少個\(p_i\) 時,可以這樣計算:
- 首先在1到n的排列中肯定有\(\lfloor n/p_i \rfloor\)個包含質因子\(p_i\)的數,同理也有\(\lfloor x/{p_i^2}\rfloor\) 個含有兩個\(p_i\)的數,不過其中的一個質因子已經在\(\lfloor n/p_i \rfloor\)中統計過,所以只需要再統計第二個質因子,即累加上\(\lfloor x/{p_i^2}\rfloor\),而不是\(2*\lfloor x/{p_i^2}\rfloor\)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const ll inf = LONG_LONG_MAX; ll n,b; ll calc(ll p,ll cnt){ //res為上述xi ll res = 0,base = 1; for(;base<=n/p;){ base*=p; res += n/base; } /*寫成下面這樣會爆 for(base=x;base<=n;base*=x){ res += n/base; }*/ return res/cnt; } int main(){ cin>>n>>b; ll ans = inf; //分解質因數 for(ll i=2;i*i<=b;i++){ if(b%i==0){ ll cnt = 0;//cnt為上述yi while(b%i==0)b/=i,cnt++; ans = min(ans,calc(i,cnt)); } } if(b>1) ans = min(ans,calc(b,1)); cout<<ans<<endl; }
D. Flood Fill
- (又是一個沒見過的區間DP,題解裏面說可以倒過來LCS,相當於求最長回文子序列,不過我還沒搞懂
d[i][j][0]
表示區間[i,j]
所有數字與a[i]
相同時所需要的最少改變次數,d[i][j][1]
表示與a[j]
相同。復雜度為\(O(n^2)\)- 每次轉移只能向左或者向右移動一格,細節看代碼吧
#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
int n;
int a[5050];
int dp[5050][5050][2];
int main(){
cin>>n;
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
if(n==1){
puts("0");return 0;
}
memset(dp,0x3f,sizeof dp);
for(int i=1;i<=n;i++)dp[i][i][0] = dp[i][i][1] = 0;
for(int i=n;i>=1;i--){
for(int j=i;j<=n;j++){
for(int k=0;k<2;k++){
//c為標準
int c = k==0?a[i]:a[j];
if(j<n)
dp[i][j+1][1] = min(dp[i][j+1][1],dp[i][j][k]+(a[j+1]==c?0:1));
if(i>1)
dp[i-1][j][0] = min(dp[i-1][j][0],dp[i][j][k]+(a[i-1]==c?0:1));
}
}
}
cout<<min(dp[1][n][0],dp[1][n][1])<<endl;
}
CF每日一練(2.11)