E - 均分纸牌
题意:给出一个长度为n的序列,序列从1开始编号,序列上的数代表这个位置上的权值,且保证所有位置上的权值之和为n的倍数。操作如下:在第一个位置上的数的权值,只能往第二个位置上移动,第n个位置上的数的权值只能往第n-1的数移动,其余左右都可。要求找到一种移动方法,用最少的移动次数使得每个位置上的权值一样。
思路:其实这道题就是贪心。比如序列: 9, 8, 17, 6,这个平均数就是10,从1位置开始,需要从右边借一个,而右边本身也差两个,最后变成差三个,那为什么不3位置直接给2位置3个,然后2位置给1两个,这样两次操作前两个数都满足了,而不是3给2一个,2给1一个,3给2两个,这样操作数就变成3了。所以只需要从左到右遍历数组,把遍历到的位置都变成aver,同时后面那个数减上(aver - a[i] ),这个公式对于,9 8 or 8 17都成立。而且题中给的交换顺序,其实没有用。
#include<iostream>
using namespace std;
typedef long long ll;
const int MAX = 1e4 + 10;
ll n, a[MAX];
int main(){
ios :: sync_with_stdio( false );
cin.tie( NULL );
cin >> n;
ll sum = 0;
for( int i = 0; i < n; i++ ){
cin >> a[i];
sum += a[i];
}
ll aver = sum / n;
ll cnt = 0;
for( int i = 0; i < n - 1; i++ ){
if( a[i] != aver ){
++cnt;
a[i + 1] -= aver - a[i];// ‘-’就很有灵魂了
a[i] = aver;
}
}
cout << cnt << endl;
return 0;
}
D - Yogurt factory 奶酪工厂
题意:生产一种物品的单价每周都在变化,而且每周都有必须的生产量,但是可以无限量无限时的保存生产的东西,但是每保存一单位的物品,每周就要多S¥(也就是每周可以多生产),问这段时间里完成任务的最小代价。
思路:这道题其实就是问,每周到底要生产多少,那就要看在这周生产是不是更便宜,即使加上存储费用。第一周当然要把必须生产的东西生产完,同时考虑是不是要多生产,而且这时是单价最小的时候,第二周有两种价钱,第一种是:最小的单价+S,第二种:这周的本身单价。选择这两种中最小的=min( 最小的+S,这周本身)。同理与第三周,所以有一种递推的感觉,我当时不知道递推找最小,就一直在疑惑到底哪个是最小啊...
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAX = 1e4 + 10;
const int INF = 0x3f3f3f3f;
ll n, s, c[MAX];
int main(){
ios :: sync_with_stdio( false );
cin.tie( NULL );
cin >> n >> s;
ll minn = INF;
ll sum = 0;
ll c, y;
for( int i = 0;i < n; i++ ){
cin >> c >> y;
minn = min( minn + s, c );//关键点
sum += minn * y;
}
cout << sum << endl;
return 0;
}
C - 蜗牛旅游
题意:给定一个长度为n的数组,找出最长不同子序列,问此序列的长度。
思路:其实这就是用队列直接进行模拟就行。用一个set建立一个集合用于记录哪些数已经进入队列,用一个queue模拟过程。只要这个数没有在队列中,就压队,每次压入就用max记录一次队列的最大长度;如果在队列中,就开始pop(包含这个数),同时要删除set集合中的数,以此来保证更新。然后再进行压入。最后输出maxx即可。
#include<iostream>
#include<algorithm>
#include<set>
#include<queue>
using namespace std;
typedef long long ll;
const int MAX = 1e6 + 10;
queue< ll > q;
set< ll > s;
ll n, num;
int main(){
ios :: sync_with_stdio( false );
cin.tie( NULL );
cin >> n;
ll maxx = -1;
for( int i = 0; i < n; i++ ){
cin >> num;
if( !s.count( num )){
s.insert( num );
q.push( num );
ll tp = q.size();
maxx = max( maxx, tp );
}
else{
while( 1 ){
if( !q.empty() && q.front() != num ){
s.erase( q.front() );
q.pop();
}
if( !q.empty() && q.front() == num ){//注意以前出现过的这个数也要删除
q.pop();
q.push( num );
break;
}
}
}
}
cout << maxx << endl;
return 0;
}
B - Text Reverse
题意:一种单词字符串:里面的单词都是翻转的,其中标点符号和单词算在一起,给出这种单词字符串,输出正常的字符串。
思路:其实就是使用栈来解决问题。然后就是注意具体实现。
#include<iostream>
#include<cstring>
#include<string>
#include<stack>
#include<vector>
#include<stdio.h>
using namespace std;
int n;
string s;
int main(){
ios :: sync_with_stdio( false );
cin.tie( NULL );
cin >> n;
cin.get();
while( n-- ){
stack< char > st;
vector< char > v;
int len;
getline(cin,s);//注意输入有空格的时候要用getline( cin, s );
int slen = s.length();
for( int i = 0; i < slen; i++ ){
if( s[i] != ' ' ){
st.push( s[i] );
}
else{
len = st.size();
for( int i = 0; i < len; i++ ){
v.push_back( st.top() );
st.pop();
}
v.push_back( ' ' );
}
}
len = st.size();
for( int i = 0; i < len; i++ ){//注意细节,后面可能还有没有用完的
v.push_back( st.top() );
st.pop();
}
len = v.size();
for( int i = 0; i < len; i++ ){
cout << v[i];
}
cout << endl;
}
return 0;
}
总结:
对于贪心这次的感觉就是要从整体出发来思考,不要只局限与局部,以及从理论到代码的实现。
对于栈、队列、优先队列,其实就是要积累经验,看看这种条件适不适合这种数据结合。要记住他们常用的函数,易错点这些。
stack:
s.clear(); //清空
s.empty(); //判断stack是否为空,为空返回true,否则返回false
s.size(); //返回stack中元素的个数
s.pop(); //删除栈顶元素,但不返回其值
s.top(); //返回栈顶元素的值,但不删除此元素
s.push(item); //在栈顶压入新元素itemqueue & priority_queue:
while (!q.empty()) q.pop(); //注意
queue & priority_queue没有清空函数
q.empty(); //判断队列是否为空
q.size(); //返回队列长度
q.push(item); //对于queue,在队尾压入一个新元素
//对于priority_queue,在基于优先级的适当位置插入新元素
//queue only:
q.front(); //返回队首元素的值,但不删除该元素
q.back(); //返回队尾元素的值,但不删除该元素
//priority_queue only:
q.top(); //返回具有最高优先级的元素值,但不删除该元素PS:
1、优先队列的本质是完全二叉树,可分为小根堆和大根堆。
2、优先队列的优先级设置:
对于node结构:priority_queue < node > q;
struct node{
int r, c, t;
node( int nr, int nc, int nt ){
r = nr;
c = nc;
t = nt;
}
friend bool operator< ( node a, node b ){
return a.t > b.t;
}};
对于int结构:priority_queue< int > p; // 默认是大根堆
priority_queue< int, vector< int >, less< int > > p; //默认是小根堆