正文
题目1
题目链接
题目大意:
给出一个整数n,求一个最大整数满足:
1、整数各个数字加起来等于n;
2、没有两个相同的数字相邻;
3、数字中不包括0;
比如说n=2,满足条件1的整数有11、2、20等,但是满足条件1、2、3的就是数字2;
输入:
第一行,整数 表示t个样例 (1≤≤1000)
每个样例一行,整数 (1≤≤1000)
输出:
每个样例输出一行,满足条件的最大整数。
Examples
input
5
1
2
3
4
5
output
1
2
21
121
212
题目解析:
题目要求的数字尽可能的大,那么数字的位数会比数字的大小更加重要,那么可以论证最终数字中不存在大于3的数字;
假如最大整数是3xx的整数,那么可以构造出来21xx使得结果更大;
同时由于条件2的存在,结果必然是以1212或者2121这样的交替结果。
为了便于计算,我们将n%3,得到一个余数q;
q=0时,结果是2121...;
q=1时,结果是12121...;
q=2时,结果是21212...;
class Solution {
static const int N = 200010;
string str;
int a[N];
public:
void solve() {
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
int k = n % 3;
if (k == 0) {
for (int i = 0; i < n / 3; ++i) {
cout << "21";
}
cout << endl;
}
else if (k == 1) {
cout << 1;
for (int i = 0; i < n / 3; ++i) {
cout << "21";
}
cout << endl;
}
else {
cout << 2;
for (int i = 0; i < n / 3; ++i) {
cout << "12";
}
cout << endl;
}
}
}
}
ac;
题目2
题目链接
题目大意:
餐馆有三种食物,数量分别是a、b、c个;
餐馆给客人提供就餐的特点:
1、每个人至少吃到一种食物;
2、每个人,每种食物最多吃1个;
3、每个人要吃不同组合的食物;
问,最多能给几个人提供就餐服务?
输入:
第一行,整数,表示样例个数 (1≤≤500)
接下来t个样例,每个1行,整数 , and (0≤,,≤10)
输出:
每个样例1行,能提供就餐服务的最多人数;
Examples
input
7
1 2 1
0 0 0
9 1 7
2 2 3
2 3 2
3 2 2
4 4 4
output
3
0
4
5
5
5
7
题目解析:
用1来表示分配,0表示不分配。
每种食物,单独分给1个人,肯定是最优的,可以优先分配;(100,010,001)
食物两两组合的时候,优先考虑剩下量最大的一种;(011,101,110)
如果还有剩下食物和人,则考虑分配3种食物的情况;(111)
int main(int argc, const char * argv[]) {
// insert code here...
int t;
cin >> t;
while (t--) {
int a[3];
cin >> a[0] >> a[1] >> a[2];
int cnt = 0;
for (int i = 0; i < 3; ++i) {
if (a[i]) {
--a[i];
++cnt;
}
}
sort(a, a+3, cmp);
for (int i = 0; i < 3; ++i) {
for (int j = i + 1; j < 3; ++j) {
if (a[i] && a[j]) {
--a[i];
--a[j];
++cnt;
}
}
}
if (a[0]&&a[1]&&a[2]) {
++cnt;
}
cout << cnt << endl;
}
return 0;
}
题目3
题目链接
题目大意:
n个人参加比赛,比赛分上半场和下半场,分别会产生1~n的名次;(没人并列)
最终的比赛排名,是根据两场比赛的名次之和进行排列;
比如说小明参加5个人的比赛,上半场和下半场分别拿了第1名和第3名,名次之和是4,那么有两种可能性,
最好的情况:
最坏的情况:
现已知小明的上下半场的名次分别是x和y,最好和最坏的名次,分别是多少?
输入:
第一行,整数,表示样例个数 (1≤≤100)
接下来t行,每行有整数, , (1≤≤10^9, 1≤,≤)
输出:
每个样例一行,两个整数,分别表示最好和最坏的名次
Examples
input
1
5 1 3
output
1 3
题目解析: 如果是名次最差的情况,那么只需要尽可能分配其他的名次,使得名次之和大于等于小明; 题目链接 输入: 输出: Examples 题目解析: 思考: 题目链接 输入: 输出: Examples 题目解析: 同理,我们用dpRight[i]来表示从i到n的数字,保持非严格递减的数字;同样可以得到dpRight[i] = dpRight[k]+(k-i)*a[i]; 思考:
分两种情况来考虑,先看�名次最好的情况;(a、b顺序没有关系,我们另a 假设n个人,小明的名次是a+b,那么应该尽量安排其他人的名次>=a+b+1,我们另k=a+b+1;
k<=n的时候,其他人可以一大一小(n配1、n-1配2这样),那小明最好的名次是1;
如果k>n的时候,有k-n-1个人,肯定无法分配使得名次比小明差,我们把这些人提取出来,小配小,比如说1配1,2配2;(贪心的思想)
又因为小明本身占用了名次a和b,如果b还在剩下的名次里面,还要占用一个名额,小明最好的名次是k-n-1-1;如果b
小明的名次之和是k=a+b,如果k>n,则必然是最后一名;(其他人可以1配n,2配n-1这样)
如果kint main(int argc, const char * argv[]) {
// insert code here...
int t;
cin >> t;
while (t--) {
int n, a, b;
cin >> n >> a >> b;
if (a > b) {
swap(a, b);
}
int ansFirst, ansLast;
int k = a + b + 1;
if (k <= n) {
ansFirst = 1;
}
else {
ansFirst = k - n - 1;
if (b >= k - n) {
++ansFirst;
}
}
int x = a + b;
if (x > n) {
ansLast = n;
}
else {
ansLast = x - 1;
}
cout << ansFirst << " " << ansLast << endl;
}
return 0;
}
题目4
题目大意:
建筑公司要建n栋楼(排成一行),第i栋的设计最大高度是m[i];
并且当地城市有规定:每栋楼不能在左右两边同时出现比它高的建筑;
用数学的语言来描述,即是每栋楼的最终高度a[i]必须要小于等于m[i];不能存在j和k,满足ja[i] 现在想知道建筑公司如何分配每栋楼的高度,使得最终所有楼的总高度最大?
第一行整数 (1≤≤1000)
第二行整数1,2,…, (1≤≤10^9)
n个整数a[i],如果有多个分配组合,输出任何一个总高度最大的组合;
input
5
1 2 3 2 1
output
1 2 3 2 1
根据题目的要求,可以知道最终的高度,是一个递增再递减的序列;
即是存在k,从k到1,数字逐渐递减;从k到n,数字逐渐递增;
由于题目n范围较小,枚举这个k,既可以知道最优解;
注意题目范围, 数字之和会超过int32;
int a[N], ans[N], f[N];
int main(int argc, const char * argv[]) {
// insert code here...
int n;
cin >> n;
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
lld sumMax = 0;
for (int k = 0; k < n; ++k) {
f[k] = a[k];
int tmp = k - 1;
while (tmp >= 0) {
f[tmp] = min(a[tmp], f[tmp + 1]);
--tmp;
}
tmp = k + 1;
while (tmp < n) {
f[tmp] = min(a[tmp], f[tmp - 1]);
++tmp;
}
lld sumTmp = 0;
for (int i = 0; i < n; ++i) {
sumTmp += f[i];
}
if (sumTmp > sumMax) {
sumMax = sumTmp;
memcpy(ans, f, sizeof(int) * n);
}
}
for (int i = 0; i < n; ++i) {
cout << ans[i] << " ";
}
cout << endl;
return 0;
}
题目5
题目大意:
建筑公司要建n栋楼(排成一行),第i栋的设计最大高度是m[i];
并且当地城市有规定:每栋楼不能在左右两边同时出现比它高的建筑;
用数学的语言来描述,即是每栋楼的最终高度a[i]必须要小于等于m[i];不能存在j和k,满足ja[i] 现在想知道建筑公司如何分配每栋楼的高度,使得最终所有楼的总高度最大?
第一行整数 (1≤≤500000)
第二行整数1,2,…, (1≤≤10^9)
n个整数a[i],如果有多个分配组合,输出任何一个总高度最大的组合;
input
5
1 2 3 2 1
output
1 2 3 2 1
由前面可以知道,最终结果必然是由一段非严格递增的数字,加上一段非严格递减的数字;
我们用dpLeft[i]来表示前i个数字,保持非严格递增的最大高度总和,那么有dpLeft[i]可以由dpLeft[1]到dpLeft[i-1]算出来;这个状态转移的复杂度是O(N);
以样例的数据来看,当我们在计算1、2、3这个三个数字的dpLeft[3]的时候,dpLeft[3]可以直接由dpLeft[2]来递推;
从i-1开始,找到第一个比a[i]小的数字k,我们有dpLeft[i]=dpLeft[k]+(i - k) * a[i];
然后遍历1~n,ans=max(ans, dpLeft[i] + dpRight[n+1]);
得到最大的结果。
单调性是进阶必备。lld a[N], dpLeft[N], dpRight[N], ans[N];
stack