先补上前两天的学习总结,假装现在是10.9.
今天复习了hja的讲课内容,总结出重要的有3点,第一点是比赛的对于long long int的应用,代码如下
#ifdef WIN32
# define lld "%I64d"
#else
# define lld "%lld"
#endif
...
int main() {
...
printf(lld "\n", answer);
}
第二点是关于NOIP 2013的积木问题
有一行 n 个坑, 每个坑的大小为 ai. 每次操作可以往编号连续的一些坑 里填一单位土. 坑里土不可溢出. 问最小操作数. n≤ 105. 有 O(n) 的简便方法。
每次选择剩余的大小最小的坑, 把它填满, 并把它左右所有可填的坑都 填一下. 依此类推.复杂度是 O( n 个坑 ∗ 填坑计算的复杂度 ).
一个坑已经被填了多少土取决于它左右最近的已经被填过的坑的大小. 如何快速找到” 左右最近” ?
我们需要想一种策略能应对多样的数据,接下来就要开始说说贪心的可行性了:我们可以把当前的高度与前面一个的高度比较,倘若比前面的高,那我们就需要在前面的高度上在向上盖,倘若比前面的低,那么前面的在盖的时候一定可以把当前位置达到目标,所以我们只需要累加所有h[i] - h[i] > 0 的值即为答案。我们在回到那个1 的问题,正是因为每次加一才能这样贪心,如果每次的高度自定的话,显然是不可行的,一旦有空的高度就一定会错误。
附代码。
#include<cstdio>
#include<iostream>
using namespace std;
int a[100000];
int min(int x,int y){if(x>=y)return y;else return x;}
int main()
{
int n,m,t,ans=0;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)
{
ans+=a[i];
ans-=min(a[i],a[i-1]);
}
cout<<ans;
return 0;
}
第三点是贪心的钩码模型
你有一堆钩码. 每个钩码有质量 wi 和承重 li. 你要把它们串成一串. 设 i 的下面的所有钩码的质量是 mi. 最小化最大的 mi−li.
假设 i 在 j 上面. 原题的实质为
max{−lj,wj−li} < max{−li,wi−lj}
假设 i 在 j 上面. 原题的实质为
max{−lj,wj−li} < max{−li,wi−lj}
显然
−lj < wi−lj,wj−li > −li
所以只需要
wj−li < wi−lj
即
wj +lj < wi +li
就变成按 wi +li 排序了. 很反直觉有木有.
今天先到这里了,晚安
补坑,附上归并排序求逆序对的程序
#include<cstdio>
#include<iostream>
using namespace std;
const int maxn = 100003;
int a[maxn], tmp[maxn],n;
long long ans = 0;
void getInverse(int l, int r) {
if (l + 1 == r) {
return;
}
int md((l + r) >> 1);
getInverse(l, md);
getInverse(md, r);
for (int i = l, j = md, k = l; i < md || j < r;) {
if (i < md && (j == r || a[i] <= a[j])) {
tmp[k ++] = a[i ++];
} else {
ans +=md-i;
tmp[k ++] = a[j ++];
}
}
for (int i = l; i < r; ++ i) {
a[i] = tmp[i];
}
}
int main()
{
//freopen("std.in","r",stdin);
//freopen("dp.out","w",stdout);
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
getInverse(1,n);
for (int i=1;i<=n;i++)
cout<<a[i];
cout<<endl<<ans;
//fclose(stdin);
//fclose(stdout);
}