第一版:
具体知识总结。
数据结构方面:
这个暑假大概花费了15*1.5小时的时间来看数据结构那本黑皮书,了解了其中基础的数据结构,其中包括最基本的线性表结构,顺序表结构,链表结构,栈结构,队列结构,树结构(这个感觉还是不太好,主要搞了搞二叉树中的完全二叉树,理解了一下关于二叉树的基本性质),还有比较基础的图结构(给人的感觉是类似python中的字典)。
至于基本的算法方面,在暑假之前,虽然感觉贪心算法比较简单(暴力我就不说了,这个暑假刷了不少,有时候需要注意一下大数的问题),但是碰上题之后老是不知道具体要求怎么写,可以说这方面的题有难的也有简单的,我觉的,这个算法的最基本的思想是(一直取对结果最好的选择)具体的题目我会在板块二中列出。
分冶算法,也算是比较基础的算法的一种,和动态规划不同的是,虽然都是把大问题分解成比较小的问题,但是分冶算法分解成的子问题之间是互相不关联的,和动态规划有一些不同,具体题目同上。
快速幂这方面,今年过年做题的时候实在被搞得十分头大所以自己写了一篇博客用于帮助记忆,emmmm,现在做题的时候就算是没有说取余啥的也直接就上那种取余的快速幂算法了,说起来,在牛客的第二场比赛中,还接收到了一个欧拉降幂写成的快速幂(emmm)感觉是真的神奇,一会把题目贴在第二版上。
还有,这个暑假也对交互式题目做了几个,这里边stl发挥作用的可能性太大了,现在开数组的时候第一时间想到的基本就是vector,string之类的,这个寒假做题的时候,还接触到了一些比较神奇的小玩意儿,比如说deque(双向队列,模拟连续开辟空间),话说这之前我还真的不知道list的模板STL也给出来了,啧啧。其中感觉比较有用的,大数类算一个,vector算一个,这两个用的比较多。
还比较有意思的是看了看结构体的多种使用,可以自定义对象的加减乘除和大小比较,甚至还能定义输出,这样就可以直接用sort了,这儿是过年前从紫薯上看的,一会贴出来,还蛮有意思的,还有就是重新看了看那个sstream的那个流操作,之前那个查字典的题的时候好用的不得了,一会也按顺序贴出来。
说起来,这个寒假看的最多的因该是属动态规划不可了(有一次cf不是贪心就是动归简直心态爆炸。。。话说我马上就灰名了啊啊啊啊啊),这个是用巫俊泽的那本书(群文件里面那本),紫薯(自己买的),还有之前牛老板发的背包九讲,明明之后每道题都能看懂,为啥现在自己写就写不出来嘞(流泪),深搜和广搜时间复杂度又大,写出来了也会超时,也只有每天默默刷题才能过得下去这个样子。(话说就是练的少吧23333333)。
板块一总结:以上是该假期大致的学习方向,怎么说呢,初一之前还是很勤奋的,每天除了做咱们vj上挂的题还会自己看紫薯和上洛谷玩耍总共六七个小时这个样子,过年之后好像比较懈怠了一点,平均每天的做题量只有两道,大部分还是水题(比如二分暴力取余二进制稍微想上个十几分钟就能做出来的),动态规划每天看以一会之前写的总结(这个真的不敢放啊,感觉啥都不会啊)。数学方面暑假自己从图书馆里借了两本线代的数学学了一些,但是目前还没有做过这样的题,倒是之前被一波波水题坑的思维比之前刚接触acm的时候好了不少(所谓被坑多了就理解挖坑人了),总之现在马上快要开学了,数学方面不能落下,acm我也会一直坚持下去的,大佬们不要抛弃我啊啊啊啊啊啊啊。
板块二:模板以及具体的题目
咱们就按上面的顺序一个个来吧。
一个难的一个简单的贪心:
先来个简单的吧。
这是个洛谷上的题:
由于乳制品产业利润很低,所以降低原材料(牛奶)价格就变得十分重要。帮助Marry乳业找到最优的牛奶采购方案。
Marry乳业从一些奶农手中采购牛奶,并且每一位奶农为乳制品加工企业提供的价格是不同的。此外,就像每头奶牛每天只能挤出固定数量的奶,每位奶农每天能提供的牛奶数量是一定的。每天Marry乳业可以从奶农手中采购到小于或者等于奶农最大产量的整数数量的牛奶。
给出Marry乳业每天对牛奶的需求量,还有每位奶农提供的牛奶单价和产量。计算采购足够数量的牛奶所需的最小花费。
注:每天所有奶农的总产量大于Marry乳业的需求量。:
题目分析,条件一:收购的可以选择从乃融的手中采购小于或者等于的羊奶。
条件二:每位奶农的产奶量和单价是不同的,所以我们可以做一个结构体,记录奶的产量和单价。
typedef long long ll;
struct node
{
ll a,b;
};//此乃牛奶的单价和产量,之后开一个结构体数组记录。
之后我们需要写一个bool函数cmp,从而使得排完序成为按照价格的顺序排序的,之后按人头一单位一单位的买,那个卖完了换人继续就行。太简单就不贴了。
我们现在来开一个比价恶心(我自认,对于大佬来说肯定不算事)的贪心:
有(N+1)个城市,0是起点N是终点,开车从0 -> 1 - > 2… -> N,车每走1个单位距离消耗1个单位的汽油,油箱的容量是T。给出每个城市到下一个城市的距离D,以及当地的油价P,求走完整个旅途最少的花费。如果无法从起点到达终点输出-1。
例如D = {10, 9, 8}, P = {2, 1, 3},T = 15,最小花费为41,在0加上10个单位的汽油,在1加满15个单位的汽油,在2加2个单位的汽油,走到终点时恰好用完所有汽油,花费为10 * 2 + 15 * 1 + 2 * 3 = 41。
Input
第1行:2个数N, T中间用空格分隔,N + 1为城市的数量,T为油箱的容量(2 <= N <= 100000, 1 <= T <= 10^9)。
第2至N + 1行:每行2个数Di, Pi,中间用空格分隔,分别表示到下一个城市的距离和当地的油价(1 <= Di, Pi
<= 1000000)。
Output
输出走完整个旅程的最小花费,如果无法从起点到达终点输出-1。
Sample Input
3 15
10 2
9 1
8 3
Sample Output
41
题目分析:
这个感觉贪心已经不是最难受的地方了。。。(毕竟感觉跟第二次网络赛的第一题差不多的思想),麻烦的是数据的处理与保留,当时wa的让人”治愈”,看完题解后理了一会才理清楚
我们需要保存前面油价比较便宜的站点,考虑当前的站点是,有限加前面的站点还可以加的油量,并且每次仅加到刚好能到达下一个站的油量,多余的保存起来。
int main()
{
int n,t,ok = 1,l = 1,r = 1;
LL ans = 0;
scanf("%d %d",&n,&t);
while(n--){
int x,y,sum = 0;
scanf("%d %d",&x,&y);
if(x > t) ok = 0;
if(!ok) continue;
for(int i = l; i < r; i++)
if(p[i] < y) sum += d[i]; // 前面的站的油比当前站便宜,优先加
else r = i; // 不比当前站便宜,没必要在前面站加
if(sum < t) d[r] = t - sum,p[r++] = y; // 当前站可以加油,再跑多远
while(l <= r && x)
if(x < d[l]) ans += (LL)x * p[l],d[l] -= x,x = 0; // 优先在前面站加,因为维护的数组前面的比后面的要便宜
else ans += (LL)d[l] * p[l],x -= d[l++];
}
if(ok) printf("%lld\n",ans);
else puts("-1");
return 0;
}
怎么说呢,总是会收到前后有关联的题目的影响,(比如动态规划)有时候并不知道贪心就能这样做出来,就是靠感觉走,不太能想到该怎么走最便宜,当时做题的时候就卡在那里了。
分冶:比如称量几枚硬币之中的假硬币这种题,就是先分成两堆,然后挑出异常的继续称这样的题,本身没有太大的难度,这里拿出来只是为了和dp形成个鲜明对比,前后的决策之间没有关系。
那个快速幂,我只能感叹一下数学的博大精深。。。
当时看见的一个用快速幂的题,发现("▔□▔)肿么跟我学的那个快速幂长得这么不一样,今天看别人写的代码,顺便总结一下快速幂的用法。。
1.先上一个普通的取模的快速幂。。。
一般的模板
ll pow(ll a, ll b, ll mod)
{
ll r = 1;
a = a % mod;
while (b > 0)
{
if (b & 1 == 1)r = (r*a) % mod;
b >>= 1;
a = (a*a) % mod;
}
return r;
}
再来一个昨天看的大神的代码。。
2.
#pragma warning(disable:4996)
#include <iostream>
#include <cstring>
#include <stdio.h>
#include <string>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
ll oula(ll n)
{
ll s = n;
for (int i = 2; i*i <= n; i++)
{
if (n%i == 0)
{
s = s / i * (i - 1);
while (n%i == 0)n /= i;
}
}
if (n > 1)s = s / n * (n - 1);
return s;
}
ll kuickpow(ll x, ll y)
{
ll ans = 1;
while (y)
{
if (y & 1)ans = (ans*x) % mod;
y >>= 1;
x = (x*x) % mod;
}
return ans;
}
int main()
{
ll n, k, a, b, sum;
scanf("%lld%lld%lld%lld", &n, &k, &a, &b);
sum = n * oula(n) / 2 % mod;
printf("%lld\n", (a + b)*kuickpow(k, sum) % mod);
return 0;
}
这里运用了一个公式是 ax=a(x%φ(m)+ φ(m))(mod m)
证明的话可以在这个链接里面看看
https://blog.youkuaiyun.com/synapse7/article/details/19610361。。。
感觉自己还差得远。。。。。
stl这块拿出个不太常见的吧。。。。什么vector和queue还有stack啥的平时用的太多了,了解了解deque和list吧,也挺方便的。用stl时候特别特别需要注意的是:迭代器是独立的一种数据形式(类),跟地址有一些区别,下面这个题就用了STL里面某些操作会返回迭代器的用法做出来的。
uva11988,用STL的list写的,感觉比较简单,运用了l.insert()会返回插入位置的迭代器的原理
#pragma warning(disable:4996)
#include <cstdio>
#include <cstring>
#include <list>
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s;
list<char>l;
while (cin >> s)
{
int n = s.size();
list<char>::iterator it = l.begin();
for (int i = 0; i < n; i++)
{
char c = s[i];
if (c == '[')it = l.begin();
else if (c == ']')it = l.end();
else {
it=l.insert(it, c);
it++;
}
}
for (it = l.begin(); it != l.end(); it++)
{
cout << *it;
}
cout << endl;
}
return 0;
}
还有结构体这块,虽然可以直接从紫薯上看,但我这里还是贴出来吧,反正也不太麻烦,就是新学个定义的方法而已,比赛的时候感觉一般也用不太上,不过如果程序比较大的话,还是比较实用的感觉。
#include <iostream>
#include <stdio.h>
#include <cstring>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <set>
#include <queue>
#include <stack>
#include <cmath>
#include <cctype>
#include <sstream>
using namespace std;
typedef long long ll;
const int maxn = 123456;
const int inf = 0x3f3f3f3f;
struct student
{
int x;
int y;
student(int x = 0, int y = 0) :x(x), y(y) {}
};
bool operator < (const student&A, const student&B)
{
return A.x < B.x;
}
ostream& operator <<(ostream&out, const student& ST)
{
out << "(" << ST.x << "," << ST.y << ")";
return out;
}
vector<student>v;
int main()
{
int n = 5;
for (int i = 0; i < n; i++)
{
int x, y;
cin >> x >> y;
student ST;
ST.x = x;
ST.y = y;
v.push_back(ST);
}
sort(v.begin(), v.end());
for (int i = 0; i < n; i++)
{
cout << v[i] << endl;
}
return 0;
}
自己定义了结构体比较大小的方法。。之后sort啊,优先队列啊啥的就能自己写了。。。
最后这个动态规划,来个目前比较和自身水平合适的吧。。。。
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能超过前一发的高度.某天,雷达捕捉到敌国的导弹来袭.由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹.
怎么办呢?多搞几套系统呗!你说说倒蛮容易,成本呢?成本是个大问题啊.所以俺就到这里来求救了,请帮助计算一下最少需要多少套拦截系统.
Input
输入若干组数据.每组数据包括:导弹总个数(正整数),导弹依此飞来的高度(雷达给出的高度数据是不大于30000的正整数,用空格分隔)
Output
对应每组数据输出拦截所有导弹最少要配备多少套这种导弹拦截系统.
Sample Input
8 389 207 155 300 299 170 158 65
Sample Output
2
————————————————————————————————————————————————
其实就是求这个数列的最大连续上升子序列的长度=_=。。。。说白了就是动态规划。
————————————————————————————————————————————————
代码如下
/*发现了么?其实就是求最大长度的上升子序列的说*/
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cstring>
using namespace std;
#define maxn 10005
int a[maxn];
int dp[maxn];
int n;
int main()
{
while (cin >> n)
{
int res = 0;
memset(dp, 0, sizeof(dp));
for (int i = 0; i < n; i++)
{
cin >> a[i];
}
for (int i = 0; i < n; i++)
{
dp[i] = 1;
}
for (int i = 0; i < n; i++)
{
for (int j = 0; j < i; j++)
{
if (a[j] < a[i])
{
dp[i] = max(dp[i], dp[j] + 1);
}
}
res = max(res, dp[i]);
}
cout << res << endl;
}
return 0;
}
革命尚未成功,同志还需努力,假期做了大概一百多道题,确实比暑假之前熟悉了不少,但是还是不够,博客啥的都是自己写的,水平也不高,模板也是自己试出来的,比较容易自己记住但是不能保证对别人的效果,我就是交个假期总结而已。。。。