QhelDIV

@____@

[HAOI2007] 上升序列

总是想得很复杂,其实很简单。

用O(n2)或者O(nlogn)的时间复杂度统计出fi即以i开始的最长上升序列是多少

因为字典序的缘故,暴力找最优解

假设某次询问是a,给定的数列是{Ai}

对于第一个位置,为了使字典序最小,我们一定选最早的i,使得fi1>=a

对于第二个位置,Ai2一定 且fi1>=a-1所以接着向后找第一个满足着两个条件的位置

……

这一段的代码:

 

	for(int i=1;i<=M;i++){
	int j,a,b,pr;
		fin>>a;
		b=0;
		A[pr=0]=-1;
		for(j=1;j<=N;j++)
			if(f[j]>=a && A[j]>A[pr]){
				Ans[++b]=j;
				a--;
				if(!a)
					break;
				pr=j;
			}
		if(b<a){
			fout<<"Impossible\n";
			continue;
		}
		for(j=1;j<=b;j++)
			fout<<A[Ans[j]]<<" ";
		fout<<endl;
	}

[USACO 4.3]Buy Low,Buy Lower

先声明一下下述的变量

N为总天数,

A[i]表示第i个数字,

f[i]和g[i]的定义见下文

Max=max(f[i])1<=i<=N

 

第一问就是个最简单的最长下降序列,f[i]表示当前包含第i个数字的最长下降序列,

第二问稍复杂,我的分析:

  1. 如果没有不能重复这个限制,非常好想到用g[i]存储当前包括第i个数字的最长下降序列的个数
    1. 如果f[i]被f[j]+1(j<i)更新,g[i]就更新为g[j]
    2. 如果f[i]等于f[j]+1,g[i]就更新为g[i]+g[j]
    3. 最后输出的方案数就是∑g[i] (f[i]=Max,1<=i<=N)
  2. 如果加上不能重复这个限制,想一想会发现对于任意两个相同的数字A[i]和A[j](j<i),如果A[i-1]的值已经求出,那么之后的任何f[i]值都用不到A[j]了,因为f[i]>=f[j] 且 g[i]>=g[j],所以遇到A[i]=A[j]的情况就把A[j]标记为不可用,以后动态规划的时候就跳过j,这样就避免了重复,一下将证明该算法的正确性(分成两个独立的部分)
    1. 用数学归纳证明按照上述做法,当程序结束时g[i]表示的序列总数中没有任何重复:
      1. 首先对于i=1时,f[i]=1,g[i]=1只有一种方案,所以没有重复
      2. 对于N≥i>1,假设当前要求f[i]和g[i],那么对于1<=j<i的g[j]都是没有任何重复的(归纳假设)
      3. 只有A[j]>A[i]且f[i]=f[j]+1时才有可能发生重复,因为g[j]没有任何重复,所以g[i]有重复当且仅当枚举j的时候有A[j1]=A[j2]且j1≠j2(举个例子:3 2 1 3 2 1,要求f[6]和g[6],当j1,j2取1,4或2,5时显然重复了).
      4. 每遇到A[i]=A[j]就把A[j]删去,保证了数列元素唯一性
      5. 按照上述做法 可以做到没有j1,j2(j1≠j2)使得A[j1]=A[j2](因为数列保证了元素的唯一性) , 那么g[i]也是没有任何重复的.
      6. 注:其实上面的话可以简述为:因为算法保证了元素单调性,所以不可能发生重复
    2. 接下来证明g[i]没有少也没多计算任何情况(算出的g[i]是正确的)
      1. 容易看出g[i]不会比正确的结果大(删除序列元素不会增加答案)
      2. 假设某个被删除的元素为A[j],那么肯定有A[i]=A[j](i>j),而g[i]包括了g[j]的所有情况(g[i]≥g[j]),所以不会有任何一种非重复情况被遗漏
      3. 综上,算出的g[i]是正确的

我的代码(因为答案可能很大,所以用了高精度,并重载了"+"运算

 

继续阅读