目录
合并果子:
题面精简:
给出一个长为n的序列,合并a和b需要a+b点能量,求和并成一个值需要多少能量?
n <= 10000,ai <= 20000
time:10ms
memory:128MiB
思路:
很简单的题,只要每次都选最小的两个数合并,就能实现最优解。
但是,题目数据过大,时限只有10ms,暴力和dp都用不上。
我们可以开一个优先队列,所有数字都从大到小排列。存数时存入负数,这样队头元素永远是最小的那个。
然后的操作就非常无脑了。
代码:
#include<iostream>
#include<queue>
using namespace std;
priority_queue <int> fruit;
int num,ans,sum;
int readint()
{
char ch = getchar();
int value = 0,sign = 1;
while(ch < '0' || ch > '9')
{
if(ch == '-') sign = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') value = value * 10 + (int)(ch) - '0',ch = getchar();
return value * sign;
}
void writeint(int value)
{
if(value < 0) putchar('-'),value *= -1;
if(value > 9) writeint(value / 10);
putchar(value % 10 + '0');
}
int main()
{
num = readint();
for(int i = 1;i <= num;i++) fruit.push(-readint());
for(int i = 1;i < num;i++)
{
sum = fruit.top();
ans -= fruit.top();
fruit.pop();
sum += fruit.top();
ans -= fruit.top();
fruit.pop();
fruit.push(sum);
}
writeint(ans);
}
田忌赛马:
题面精简:
给出多组的n,以及n个我方速度和n个敌方速度,要求胜场和败场的差越大越好,结果乘以200
n <= 2000
time:1000ms
memory:256MiB
思路:
这题很经典,n匹马的比赛非常难算,用dp实现非常困难。
如果用队列的话,有一种很好理解的思路。
开两个数组,代表田忌的马和齐王的马,设置两个头节点和两个尾节点,然后把两个数组排序。
由此,头结点代表最慢的马,尾节点代表最快的马。
如果尾结点1代表的马比尾结点2代表的马要快,就解决掉它,这样才能让快马派上快的用途。
如果不足的话,就看头结点1的马是否可以击败头结点2的马,如果可以,就解决掉他,这样慢马也有了贡献。
调整节点位置后,继续执行直到头结点超过尾结点。
再不然,就要考虑特殊情况,如果头结点1的马不能和尾结点2的马打平,就只能拿最慢的马当炮灰了,这没办法啊。
三个if语句就能轻而易举得到答案。
代码:
#include<iostream>
#include<algorithm>
using namespace std;
int read()
{
int ans = 0,var = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-') var = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') ans *= 10,ans += (int)(ch) - '0',ch = getchar();
return ans * var;
}
void writeint(int output)
{
if(output < 0) putchar('-'),output *= -1;
if(output > 9) writeint(output / 10);
putchar(output % 10 + '0');
}
int horse,tj[2003],qw[2003],head_tj,head_qw,tail_tj,tail_qw,win;
int main()
{
while(horse = read())
{
win = 0;
head_tj = 1,head_qw = 1;
tail_tj = horse,tail_qw = horse;
if(!horse) return 0;
for(int i = 1;i <= horse;i++) tj[i] = read();
for(int i = 1;i <= horse;i++) qw[i] = read();
sort(tj + 1,tj + 1 + horse);
sort(qw + 1,qw + 1 + horse);
while(horse--)
{
if(tj[tail_tj] > qw[tail_qw])
{
tail_tj--;
tail_qw--;
win++;
}
else if(tj[head_tj] > qw[head_qw])
{
head_tj++;
head_qw++;
win++;
}
else if(tj[head_tj] < qw[tail_qw])
{
head_tj++;
tail_qw--;
win--;
}
}
writeint(win * 200);
putchar('\n');
}
}
丑数:
题面精简:
给出一个有k个元素的集合,求出第n个所有因数都属于这个集合的数。
k <= 100;
n <= 100000
time:5000ms
memory:256MiB
通常,限制超过正常值的题目,都十分的变态,但这道题真的简单,更难的我都不会做,有兴趣的可以一试。
思路:
与其被动去寻找丑数,不如自己生成。
为了让丑数序列升序排列,我们需要一些黑科技。
设置两个数组:value和lable,存放因子的值和目前指向的指针(默认为1),ans数组存放丑数序列(ans[1]默认为1)。
每次找到最小的值(value[i] * ans[lable[i]]),存在ans数组顶。然后找到某个value[i] * ans[lable[i]]和最小值相等,把lable[i]加上1。
再找最小数的过程中,如果遇到某个表达式的值和目前的最小值相等,也把lable[i]加上1。
运行n + 1次后,退出循环,输出ans[n + 1]。
代码:
#include<iostream>
using namespace std;
int read()
{
int ans = 0,var = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-') var = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') ans *= 10,ans += (int)(ch) - '0',ch = getchar();
return ans * var;
}
void write(int output)
{
if(output < 0) putchar('-'),output *= -1;
if(output > 9) write(output / 10);
putchar(output % 10 + '0');
}
int num,x_th,value[102],lable[102],ans[100005],len;
int main()
{
num = read();
x_th = read();
for(int i = 1;i <= num;i++)
{
value[i] = read();
lable[i] = 1;
}
ans[++len] = 1;
while(len <= x_th + 1)
{
long long minn = 1000000000000;
for(int i = 1;i <= num;i++)
{
if(ans[lable[i]] * value[i] < minn) minn = ans[lable[i]] * value[i];
else if(ans[lable[i]] * value[i] == minn) lable[i]++;
}
ans[++len] = minn;
for(int i = 1;i <= num;i++) if(minn == value[i] * ans[lable[i]]) lable[i]++;
}
write(ans[x_th + 1]);
}