Arranging Hat is a cushy job indeed; high impact work, absolute authority, and 364 days of holiday every year. However, the hat has decided that it can do even better—it would like very much to become a tenured professor. Recently the hat has been reading computer science papers in its ample spare time, and of course, being an arranging hat, it is particularly interested in learning more about sorting algorithms.
The hat’s new contribution is to a class of algorithms known as lossy sorting algorithms. These usually work by removing some of the input elements in order to make it easier to sort the input (e.g., the Dropsort algorithm), instead of sorting all the input.
The hat is going to go one better—it is going to invent a lossy sorting algorithm for numbers that does not remove any input numbers and even keeps them in their original place, but instead changes some of the digits in the numbers to make the list sorted.
The lossiness of the sorting operation depends on how many digits are changed. What is the smallest number of digits that need to be changed in one such list of numbers, to ensure that it is sorted?
题目大意:给你n个长度为m的正整数,你需要改变最少次数使其成为递增。
思路:明显的dp题,dp[i][j] 表示前i个数改变j次得到的第i个数的最小值,我们可以通过 dp[i][j] 贪心地得到 dp[i+1][j+k] 的最小值,前i个数我们最多可以改变i*m次,那么我们开的数组为 dp[n][n*m][m], 肯定爆空间了。但仔细想想,在最坏的情况下n为40,改变的次数最多也就10*(1+2+3+4)次。为什么?交给读者自己思考。
还有一个坑点,就是在给定次数贪心最小值。思路是从最高位开始贪心,不同的就使它们相等,直至用完次数。用完后发现还是比原数要小,就在改变的最低位加1,但前提是不能为‘9’,如果是9的话就往高位找,直至找到不为9的数令其+1,并且往后填0,当然,如果没有就返回false。
最后就是细节处理要注意了,附AC代码:
#include<bits/stdc++.h>
#define CLR(a, b) memset(a, b, sizeof(a)) using namespace std;
const int maxn = + ;
const int maxf = + ;
const int maxm = + ; char dp[maxn][maxf][maxm];
char nm[maxn][maxm];
bool val[maxn][maxf];
int pre[maxn][maxf];
int n, m; bool change(const char *a, const char *b, int lim, char *temp) {
strcpy(temp, b);
int left = lim;
int p = ;
for(p=;p<m&&left;p++) if(temp[p]!=a[p])
temp[p] = a[p], left--;
if(strcmp(temp, a)>=)
return true;
left = lim;
for(--p;p>=&&temp[p]=='';) --p;
if(p<) return false;
int pos;
strcpy(temp, b);
for(pos=;pos<p;pos++) if(temp[pos]!=a[pos])
temp[pos] = a[pos], left--;
if(temp[p]- != a[p]) {
temp[p] = a[p]+; left --;
}
for(++p;p<m&&left;p++) {
temp[p] = '';
if(temp[p]!=a[p]) left--;
}
return true;
} void print_ans(int nn, int k) {
if(!nn) return ;
print_ans(nn-, pre[nn][k]);
printf("%s\n", dp[nn][k]);
} int main() {
scanf("%d%d", &n, &m);
for(int i=;i<=n;i++)
scanf("%s", nm[i]);
CLR(dp, );
CLR(val, false);
for(int i=;i<m;i++)
dp[][][i] = '';
dp[][][m] = '\0';
val[][] = true;
char temp[maxm];
CLR(pre, );
for(int i=;i<n;i++)
for(int j=;j<maxf;j++) if(val[i][j]) {
for(int k=;k<=m && k+j < maxf;k++) {
if(change(dp[i][j], nm[i+], k, temp) &&
(!val[i+][k+j] || strcmp(temp, dp[i+][k+j]) < )) {
val[i+][k+j] = true;
strcpy(dp[i+][k+j], temp);
pre[i+][k+j] = j;
}
}
}
int sign;
for(int i=;i<maxf;i++)
if(val[n][i]) { sign = i; break; }
print_ans(n, sign);
}