数列分段 Section II
二分答案;
#include<bits/stdc++.h>
#define ll long long
#define endl "\n"
#define mem(vis, num) memset(vis, num, sizeof(vis));
using namespace std;
int a[100001], n, m;
bool check(int x){
int cnt = 1, l = 0;
for(int r = 1; r <= n; r++){
if(l + a[r] > x){
l = 0;
cnt++;
}
l += a[r];
}
return cnt <= m;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
mem(a, 0);
int l = 1, r = 1000000000;
cin >> n >> m;
for(int i = 1; i <= n; i++){
cin >> a[i];
l = max(a[i], l);
}
int ans = l;
while(l < r){
int mid = (l + r) >> 1;
if(check(mid)){
ans = mid;
r = mid;
}else{
l = mid + 1;
}
}
cout << ans;
return 0;
}
积木画
可以用待定系数法偷鸡,
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int M = 10000010;
const int mod = 1000000007;
ll dp[M];
int main(){
memset(dp, 0, sizeof(dp));
cin.tie();
cout.tie();
int n,i;
cin>> n;
dp[0] = 1;
dp[1] = 1;
dp[2] = 2;
dp[3] = 5;
dp[4] = 11;
int a = 4, b = 20;
for(i = 5;i <= n;i++){
dp[i] += dp[i - 1];
dp[i] %= mod;
dp[i] += dp[i - 1];
dp[i] %= mod;
dp[i] += dp[i - 3];
dp[i] %= mod;
}
cout << dp[n];
return 0;
}
李白打酒加强版
动态规划状态为第 i 次遇花 j 次遇店剩下 k 斗酒的不同情况数;
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int M = 110;
const int mod = 1000000007;
ll dp[M][M][M];
int main(){
cin.tie();
cout.tie();
int m, n;
cin>> n >> m;
memset(dp, 0, sizeof(dp));
dp[0][0][2] = 1;
int i = 0, j = 0, k = 0;
for(i = 0; i <= m; i++){
for(j = 0; j <= n; j++){
for(k = 0; k < 101; k++){
if(i == 0 && j == 0){
continue;
}
if(i > 0){
dp[i][j][k] += dp[i - 1][j][k + 1];
}
dp[i][j][k] %= mod;
if(j > 0 && !(k & 1)){
dp[i][j][k] += dp[i][j - 1][k >> 1];
}
dp[i][j][k] %= mod;
}
}
}
cout << dp[m - 1][n][1];
return 0;
}
砍竹子
贪心+优先队列+合并区间;
#include<bits/stdc++.h>
#define ll long long
#define endl "\n"
#define mem(vis, num) memset(vis, num, sizeof(vis));
const int N = 200010;
using namespace std;
int ans,n;
ll high[N];
struct boo{
int l, r;
ll h;
boo(int i, int j, ll k) : l(i), r(j), h(k){}
};
struct comp{
bool operator()(const boo x, const boo y){
if(x.h != y.h){
return x.h < y.h;
}else{
return x.l > y.l;
}
}
};
priority_queue <boo,vector<boo>,comp > q;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
ans = 0;
cin >> n;
int l = 1, r = 1;
for(int i = 1; i <= n; i++){
cin >> high[i];
}
for(int i = 1; i <= n; i++){
int l = i, r = i;
while(r + 1 <= n && high[r] == high[r + 1]){
r++;
}
i = r;
if(high[l] != 1){
q.push(boo(l, r, high[l]));
}
}
while(!q.empty()){
boo temp = q.top();
r = temp.r;
q.pop();
while(!q.empty() && q.top().h == temp.h && r + 1 == q.top().l){
r = q.top().r;
q.pop();
}
temp.r = r;
temp.h = (int)sqrt(temp.h / 2 + 1);
if(temp.h != 1){
q.push(temp);
}
ans++;
}
cout<<ans<<endl;
return 0;
}
数字游戏
断环成链+前缀和+区间 DP,状态定义为区间 i 到 j 分为 m 段的最优情况;
#include<bits/stdc++.h>
#define ll long long
#define endl "\n"
#define mem(vis, num) memset(vis, num, sizeof(vis));
using namespace std;
ll a[101], b[101][101][10], s[101][101][10];
int mod(int x){
return ((x % 10) + 10) % 10;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
mem(b, 0);
mem(s, 1);
int n, m;
cin >> n >> m;
for(int i = 1; i <= n; i++){
cin >> a[i];
a[i + n] = a[i];
}
for(int i = 1; i <= 2 * n; i++){
a[i] += a[i - 1];
}
for(int i = 1; i <= 2 * n; i++){
for(int j = 1; j <= 2 * n; j++){
b[i][j][1] = mod(a[j] - a[i - 1]);
s[i][j][1] = mod(a[j] - a[i - 1]);
}
}
for(int i = 1; i <= 2 * n; i++){
for(int j = i + 1; j <= 2 * n; j++){
for(int l = 2; l <= m; l++){
for(int k = i; k < j; k++){
b[i][j][l] = max(b[i][j][l], b[i][k][l - 1] * b[k + 1][j][1]);
s[i][j][l] = min(s[i][j][l], s[i][k][l - 1] * s[k + 1][j][1]);
}
}
}
}
ll maxl = 0, minl;
mem(&minl, 1);
for(int i = 1; i <= n; i++){
maxl = max(maxl, b[i][i + n - 1][m]);
minl = min(minl, s[i][i + n - 1][m]);
}
cout << minl << endl << maxl << endl;
return 0;
}
多米诺骨牌
状态表示为前 i 个骰子对的上和下和之差为 j 的最少反转次数;
#include<bits/stdc++.h>
#define ll long long
#define endl "\n"
#define mem(vis, num) memset(vis, num, sizeof(vis));
using namespace std;
int s[1001], dp[1001][10002];
const int bias = 5001;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
mem(dp, 1);
int a, b, n;
cin >> n;
for(int i = 1;i <= n ;i++){
cin >> a >> b;
s[i] = a - b;
}
dp[1][s[1] + bias] = 0;
dp[1][bias - s[1]] = 1;
for(int i = 2; i<= n;i++){
for(int j = 1; j <= 10001; j++){
if(j + s[i] >= 0 && j + s[i] <= 10001){
dp[i][j] = dp[i - 1][j + s[i]] + 1;
}
if(j - s[i] >=0 && j -s[i] <= 10001){
dp[i][j] = min(dp[i][j], dp[i - 1][j - s[i]]);
}
}
}
int ans = n;
for(int i = 0; i <= 5000; i++){
int t = min(dp[n][i + bias], dp[n][bias - i]);
if(t < ans){
ans = t;
break;
}
}
cout << ans;
return 0;
}





