連接:http://codeforces.com/contest/1114html
題意:甲乙丙三我的吃葡萄,總共有三種葡萄:綠葡萄、紫葡萄和黑葡萄,甲乙丙三我的至少要各自吃 $x,y,z$ 個葡萄,又甲只吃綠葡萄,乙不吃黑葡萄,丙三種顏色都吃。如今總共有 $a$ 個綠葡萄、$b$ 個紫葡萄、$c$ 個黑葡萄。要確認這麼多葡萄可否使得三我的都滿意。c++
題解:優先知足甲,剩下的綠葡萄加紫葡萄知足乙,最後再剩下的看看能不能知足丙。數組
AC代碼:spa
#include<bits/stdc++.h> using namespace std; int x,y,z,a,b,c; int main() { cin>>x>>y>>z>>a>>b>>c; if(a>=x && (a-x)+b>=y && a-x+b-y+c>=z) cout<<"YES\n"; else cout<<"NO\n"; }
題意:將一個長度爲 $n$ 的數組分紅 $k$ 段,每段元素至少要有 $m$ 個,設每一段都有一個「漂亮程度」爲該段的前 $m$ 大的元素之和,求如何分割這個數組,使得每一段的「漂亮程度」之和最大。code
題解:這個數組的前 $m \cdot k$ 大個元素就是答案,假設這 $m \cdot k$ 個元素的集合爲 $S$。那麼如何分割,即在原數組中枚舉,每累計遇到 $m$ 個屬於 $S$ 的元素,就在這個位置劃一刀,而後從新開始累計便可。htm
AC代碼:blog
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pii; #define mk(x,y) make_pair(x,y) #define a(p) (p.first) #define b(p) (p.second) const int maxn=2e5+5; int n,m,k; int a[maxn]; bool t[maxn]; vector<pii> v; int main() { cin>>n>>m>>k; for(int i=1;i<=n;i++) scanf("%d",&a[i]), v.push_back(mk(a[i],i)); sort(v.begin(),v.end(),greater<pii>()); memset(t,0,sizeof(t)); ll sum=0; for(int i=0;i<(m*k);i++) t[b(v[i])]=1, sum+=a(v[i]); cout<<sum<<endl; int cnt=0, seg=0; for(int i=1;i<=n;i++) { if(t[i]) cnt++; if(cnt==m) { cnt=0, seg++; if(seg<k) printf("%d ",i); } } }
題意:給定一個十進制下的 $n$,要求出 $n!$ 在 $b$ 進制下進行表示,其尾部有多少個零。ci
題解:get
換句話說,其實就是算 $n!$ 最多能整除多少次 $b$。對 $b$ 分解質因數得 $b = {p_1}^{x_1}{p_2}^{x_2} \cdots {p_k}^{x_k}$,而後只要算出 $n!$ 對應的 ${p_1}^{y_1}{p_2}^{y_2} \cdots {p_k}^{y_k}$ 就很好辦了。it
而後用十進制舉例,例如 $n = 12$,那麼先考慮 $10$ 進制的 $10 = 2 \times 5$,而後 $n / 2 = 6$ 咱們就能夠知道 $1 \sim 12$ 有 $[2,4,6,8,10,12]$ 這六個 $2$ 的倍數,每一個數至少能提供 $2$ 的 $1$ 次方,而其中又有一部分能多提供一些,即 $n / 2^2 = 3$,即有 $[4,8,12]$ 這三個數字至少能提供 $2$ 的 $2$ 次方,考慮到這三個數字前面已經計算過提供一次,因此能夠看作這三個數又提供了三個 $1$ 次方,再而後 $n / 2^3 = 12 / 8 = 1$,即 $[8]$ 這一個數字還能再多提供一個 $1$ 次方。所以總結下來,計算 $n!$ 到底包含多少個 $p_i$ 的 $x$ 次方經過 $n/p_i + n/p_i^2 + \cdots $ 就能夠算出來。
因此相似地,咱們對 $p_1 \cdots p_k$,每一個都算出 $n!$ 包含其多少次方,最後取 $\lfloor \frac{y_i}{x_i} \rfloor$ 的最小值。
AC代碼:
#include<bits/stdc++.h> using namespace std; typedef unsigned long long ull; typedef pair<ull,int> P; #define mk(x,y) make_pair(x,y) #define _1 first #define _2 second vector<P> p; void dec(ull n) { p.clear(); for(ull i=2;i*i<=n;i++) { if(n%i==0) { int cnt=0; while(n%i==0) n/=i, cnt++; p.push_back(mk(i,cnt)); } } if(n>1) p.push_back(mk(n,1)); } ull solve(ull n,ull p) { ull base=1, res=0; while(base<=n/p) { base*=p; res+=n/base; } return res; } int main() { ull n,b; cin>>n>>b; dec(b); ull ans=ULLONG_MAX; for(auto x:p) ans=min(ans,solve(n,x._1)/x._2); cout<<ans<<endl; }
題意:在一條線上給定 $n$ 個方格,每一個方格都上了一種顏色,當儘可能最長的一段的若干個連續方格顏色同樣時,能夠看作一個連通塊。咱們開始時要選擇一個起點方格,而後咱們能夠不斷地將該方格所屬的整個連通塊所有變爲另外一個顏色,每變一次算一輪,求最少多少輪可使得 $n$ 個方格變爲一個連通塊。
題解:首先咱們知道,連通塊是逐漸擴張的,並且一個連通塊的顏色,要麼是最左邊的那個方塊的顏色,要麼是最右邊的方塊的顏色。
所以記 $f[0,1][i][j]$ 表示 $[i,j]$ 區間內全部方塊變成最左側方塊顏色的最少輪次,以及變成最右側方塊顏色的最少輪次。
那麼顯然初始狀態就是全部的 $f[0,1][i][i] = 0$,而對於一個 $f[0,1][i][j]$,它多是 $f[0,1][i+1][j]$ 轉移過來的,也多是 $f[0,1][i][j-1]$ 轉移過來的,若 $c[i]=c[j]$ 的話那麼還有多是 $f[0,1][i+1][j-1]$ 轉移過來的。
AC代碼:
#include<bits/stdc++.h> using namespace std; const int maxn=5e3+5; int n,c[maxn]; int f[2][maxn][maxn]; int main() { cin>>n; for(int i=1;i<=n;i++) cin>>c[i]; memset(f,0x3f,sizeof(f)); for(int i=1;i<=n;i++) f[0][i][i]=f[1][i][i]=0; for(int len=2,tp;len<=n;len++) { for(int i=1,j=i+len-1;j<=n;i++,j++) { tp=min(f[0][i+1][j]+(c[i]!=c[i+1]),f[1][i+1][j]+(c[i]!=c[j])); f[0][i][j]=min(f[0][i][j],tp); tp=min(f[0][i][j-1]+(c[i]!=c[j]),f[1][i][j-1]+(c[j-1]!=c[j])); f[1][i][j]=min(f[1][i][j],tp); if(c[i]==c[j]) { tp=min(f[0][i+1][j-1]+(c[i+1]!=c[i]),f[1][i+1][j-1]+(c[j-1]!=c[j])); f[0][i][j]=min(f[0][i][j],tp), f[1][i][j]=min(f[1][i][j],tp); } } } cout<<min(f[0][1][n],f[1][1][n])<<endl; }
PS.做爲一個DP廢物,往往遇到DP題就很艱辛……