目录
训练链接:https://vjudge.net/contest/350406
C - Consecutive Subsequence (CodeForces 977F)
D - Easy Problem (CodeForces 1096D)
E - Flood Fill (CodeForces 1114D)
A - Boredom
题意:给出长度为的数组,每轮游戏可以进行一次操作,每次操作任选一个数(定义为
),游戏者获得
分,操作结束后,删去所有
和等于
、
的数,问游戏者最大能够获得多少分。
思路:记录每个数出现的次数(),与数组最大值(
)。
状态:表示第
个数选或不选。
状态转移方程:
选择当前数,则可以由两种状态转移过来:前一个不选(选择前2个)和选择前3个,如选择:第一个和第四个数,或者选择第二个数与第四个数。
不选择当前数,则状态等于前一个数选。
AC代码:
const int maxn = 2e5 + 5;
typedef long long LL;
LL n, a[maxn];
LL dp[maxn][2];
LL times[maxn];
int main(){
cin >> n;
LL Max = 0;
for(int i = 1; i <= n; ++i){
cin >> a[i];
times[a[i]]++;
Max = max(Max, a[i]);
}
LL ans = 0;
dp[1][1] = 1 * times[1];
dp[1][0] = 0;
dp[2][1] = dp[1][0] + 2 * times[2];
dp[2][0] = dp[1][1];
for(int i = 3; i <= Max; ++i){
dp[i][1] = max(dp[i - 3][1], dp[i - 1][0]) + i * times[i];
dp[i][0] = dp[i - 1][1];
}
ans = max(dp[Max][1], dp[Max][0]);
cout << ans << endl;
return 0;
}
B - Flowers
题意:有红色和白色两种颜色的花,Marmot的晚餐是白花,给出组测试数据与一个数
,代表着Marmot的
顿晚餐,每顿晚餐可以让餐桌上摆上
至
朵花,但是Marmot只吃长度为
的连续的白花(意味着如果
,则若是白花单独放置,Marmot不吃),所以若是将白花摆上餐桌,则必定是连续摆上
朵白花,否则只摆红花。输出
行,每行代表着这顿晚餐Marmot有多少种摆花的方法。
思路:找规律推状态。随便写几组就知道了。
AC代码:
const int maxn = 1e5 + 5;
typedef long long LL;
const LL mod = 1e9 + 7;
LL dp[maxn];
LL pre[maxn];
int main(){
int t, k;
cin >> t >> k;
//k == 1: 1 -> 2, 2 -> 4, 3 -> 8, 4 -> 16 8 + 8
//k == 2: 1 -> 1, 2 -> 2, 3 -> 3, 4 -> 5, 5 -> 8 5 + 3
//k == 3: 1 -> 1, 2 -> 1, 3 -> 2, 4 -> 3, 5 -> 4 3 + 1
//k == 4: 1 -> 1, 2 -> 1, 3 -> 1, 4 -> 2, 5 -> 3, 6 -> 4 3 + 1
// l < k -> 1, l == k -> 2, l > k -> l - 1 + l - k
for(int i = 1;i < k; ++i) dp[i] = 1, pre[i] = pre[i - 1] + dp[i];
dp[k] = 2;
pre[k] = pre[k - 1] + dp[k];
for(int i = k + 1; i <= (int)1e5; ++i) dp[i] = dp[i - 1] + dp[i - k], pre[i] = pre[i - 1] + dp[i], pre[i] %= mod, dp[i] %= mod;
//for(int i = 1; i <= 8; ++i) printf(" %lld ", dp[i]); printf("\n");
//for(int i = 1; i <= 4; ++i) printf(" %lld ", pre[i]); printf("\n");
while(t--){
int a, b;
cin >> a >> b;
LL ans = (pre[b] - pre[a - 1] + mod) % mod;
printf("%lld\n", ans);
}
return 0;
}
C - Consecutive Subsequence
题意:给出长度为的数组,输出最长连续上升子序列,要求上升子序列的两个数差值为1。
思路:
状态:表示以
结尾的符合题意的最长上升子序列长度。
转移方程:。
遍历map,得到最长的上升子序列与数值,从后往前遍历输出。
AC代码:
#define fi first
#define se second
onst int maxn = 2e5 + 5;
map<int, int> dp;
int a[maxn];
int main(){
int n;
scanf("%d", &n);
dp.clear();
for(int i = 1; i <= n; ++i){
scanf("%d", a + i);
dp[a[i]] = max(dp[a[i]], dp[a[i] - 1] + 1);
}
map<int, int> :: iterator it;
int ans = 0;
int x;
for(it = dp.begin(); it != dp.end(); ++it){
if(ans < (it -> se)){
ans = it -> se;
x = it -> fi;
}
}
vector<int> out;
out.clear();
for(int i = n; i >= 1; --i){
if(a[i] == x){
out.pb(i);
x--;
}
if(!x) break;
}
int len = out.size();
printf("%d\n", len);
for(int i = len - 1; i >= 0; --i){
printf("%d ", out[i]);
}
printf("\n");
return 0;
}
D - Easy Problem
题意:给出长度为的字符串
,与字符串每个字符对应的权重,要求删去字符串中的一些字符,使得字符串不含“hard”子序列。删去一个字符的花费为此字符的权重,要求删除字符的权重和最小。
思路:设字符数组ch[] = {"#hard"}
状态:表示字符串
的前
个字符里 ,不含子序列
的花费,如:
表示
的前15个字符所组成的字串不含“har”子序列。
转移方程:若,则
若,则
AC代码:
#define LL long long
const int maxn = 1e5 + 5;
char s[maxn];
LL a[maxn];
LL dp[maxn][5];//前i个字符不含ch1 ~ chj;
static char ch[] = {"#hard"};
int main(){
int n;
scanf("%d", &n);
scanf(" %s", s + 1);
for(int i = 1; i <= n; ++i){
scanf("%lld", a + i);
}
for(int i = 1; i <= n; ++i) {
if(s[i] == 'h') dp[i][1] = dp[i - 1][1] + a[i];
else dp[i][1] = dp[i - 1][1];
}
for(int i = 2; i <= 4; ++i){
for(int j = 1; j <= n; ++j){
if(s[j] == ch[i]) dp[j][i] = min(dp[j - 1][i - 1], dp[j - 1][i] + a[j]);
else dp[j][i] = dp[j - 1][i];
}
}
printf("%lld\n", dp[n][4]);
return 0;
}
E - Flood Fill
题意:有个方块,每个方块有个初始的颜色
,,要求选定一个方块,然后不断进行一个操作:将选定方块所在的连通块(颜色相同的邻接方块)的颜色转化成其他颜色,问需要操作几次才能够使得所有方块的颜色一致。
思路:区间dp。
状态:表示将区间
中的所有方块转化为与第
个方块相同的颜色。
表示将区间
中的所有方块转化为与第
个方块相同的颜色。
转移方程:由
和
转移而来。
同理。
AC代码:
const int maxn = 5e3 + 5;
int c[maxn];
int dp[maxn][maxn][2];
int main(){
int n;
scanf("%d", &n);
for(int i = 1; i <= n; ++i) {
scanf(" %d", c + i);
dp[i][i][1] = dp[i][i][0] = 0;
}
for(int len = 2; len <= n; ++len){
for(int i = 1; i <= n; ++i){
int j = i + len - 1;
if(j > n) break;
dp[i][j][1] = min(dp[i + 1][j][1] + (c[i] != c[i + 1]), dp[i + 1][j][0] + (c[i] != c[j]));
dp[i][j][0] = min(dp[i][j - 1][1] + (c[i] != c[j]), dp[i][j - 1][0] + (c[j] != c[j - 1]));
}
}
int ans = min(dp[1][n][1], dp[1][n][0]);
printf("%d\n", ans);
return 0;
}