题目链接:Posterized
题意
给出 n n 个整数和一个阈值 ,所有整数都在 [0,255] [ 0 , 255 ] 的范围内,要求将所有整数分到一个不阈值大于 k k 的区间内,并从这个阈值内选出一个数字代表这个阈值中的所有数字, 内每个整数都只能属于一个阈值,问将 n n 个整数都用所属阈值的代表数字替换后,字典序最小的结果。
输入
第一行为两个整数 ,第二行为 n n 个整数 。
输出
输出字典序最小的结果。
样例
输入 |
---|
4 3 2 14 3 4 |
输出 |
0 12 3 3 |
提示 |
令 2 2 属于 ,代表数字为 0 0 , 属于 [12,14] [ 12 , 14 ] ,代表数字为 12 12 , 3,4 3 , 4 属于 [3,5] [ 3 , 5 ] ,代表数字为 3 3 ,即得到最小字典序结果。 |
输入 |
---|
5 2 0 2 1 255 254 |
输出 |
0 1 1 254 254 |
题解
最初每个数字都属于自身阈值(长度为 ),从前往后,每碰到一个数字,先检查这个数字是否已经属于某一个阈值,如果已经属于,则只能用该阈值的代表数字替换,否则往前找 k−1 k − 1 个数字,保证前 x (x≤k−1) x ( x ≤ k − 1 ) 个数字都没有属于某阈值的情况下,贪心地找到最小的能代表的数字,将这一段的代表数字同设置为该数字,一直往后。
过题代码
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <climits> #include <cstring> #include <string> #include <vector> #include <list> #include <queue> #include <stack> #include <map> #include <set> #include <functional> #include <algorithm> using namespace std; #define LL long long const int maxn = 100000 + 100; int n, k; int num[maxn]; int head[1000]; int Find(int x) { int ret = x; int kk = k; while(ret != 0) { --ret; --kk; if(head[ret] != -1) { ++ret; break; } if(kk == 0) { ++ret; break; } } if(ret == 0) { return ret; } if(x - head[ret - 1] + 1 <= k) { return head[ret - 1]; } else { return ret; } } int main() { #ifdef LOCAL freopen("test.txt", "r", stdin); // freopen("testout.txt", "w", stdout); #endif // LOCAL ios::sync_with_stdio(false); while(scanf("%d%d", &n, &k) != EOF) { memset(head, -1, sizeof(head)); for(int i = 1; i <= n; ++i) { scanf("%d", &num[i]); if(head[num[i]] != -1) { continue; } int Index = Find(num[i]); for(int j = Index; j <= num[i]; ++j) { head[j] = Index; } } for(int i = 1; i <= n; ++i) { if(i != 1) { printf(" "); } printf("%d", head[num[i]]); } printf("\n"); } return 0; }