USCAO 4.3.1 buylow 动态规划-高精度

第一问:显然是最长下降子序列


f[i] = max {f[j] + 1 }  a[i] < a[j]


这样就可以得到第一问的解。


先不考虑题目的限制条件,也就是方案重复的情况, 假如方案可以重复,有多少个解?

ans[i] = sigam {ans[j] }  其中f[j] + 1 == f[i], 同时a[i]>a[j]


加上限制条件,要怎么办呢? 如何去掉重复的情况呢?


我们考虑如下情况


6 5 [4] 9 8 [4]


到4的最长下降子序列为3, 可以6 5 4(第一个4)  也可以6 5 4(第二个4) ,也可以 9 8 4(第二个4)


显然,对于最长下降子序列为【相同】的时候,对于4这个数字,最后一个4的方案数,包含所有以4结尾,最长下降子序列为3的解的数量。 基于此,我们可以构造next数组,next[i],表示a[i]和 a[next[i]]相同。  在上面的例子里,就是next[3] = 6.


那么根据next数组,就可以得到一个解决限制条件的解法。在ans[i] = sigam {ans[j] }  的限制条件里,再加上, next[j] 存在的时候,如果next[j]小于i,这个ans[j]就不能加入在ans[i]里。


得到如下程序:

Executing...
   Test 1: TEST OK [0.003 secs, 3440 KB]
   Test 2: TEST OK [0.005 secs, 3440 KB]
   Test 3: TEST OK [0.008 secs, 3440 KB]
   Test 4: TEST OK [0.003 secs, 3440 KB]
   Test 5: TEST OK [0.014 secs, 3440 KB]
   Test 6: TEST OK [0.016 secs, 3440 KB]
   Test 7: TEST OK [0.014 secs, 3440 KB]
  > Run 8: Execution error: Your program did not produce an answer
        that was judged as correct. The program stopped at 0.005 seconds;
        it used 3440 KB of memory. Your answer length was 6; the correct
        length is 66. At character number 5, your answer says '0' while
        the correct answer says '1'. 

        Here are the respective outputs:
        ----- our output ---------
        200_1606938044258990275541962092341162602522202993782792835301376
        ---- your output ---------
        200_0
        --------------------------


/*
TASK:buylow
LANG:C++
*/

#include <cstdio>
#include <cstdlib>
#include <cstring>

const int max_n = 5000 + 10;
int n;
int a[max_n]={0x7fffffff};

void init()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; ++ i)	scanf("%d", &a[i]);
}

int f[max_n]={0}, next[max_n]={0}, ans[max_n]={1};
void doit()
{
	a[n + 1] = -0x7fffffff;
	for (int i = 1; i <= n + 1; ++ i)
		for (int j = 0; j != i; ++ j)	
			if (a[j] > a[i] && f[j] + 1 > f[i])	f[i] = f[j] + 1;
	for (int i = 1; i <= n; ++ i)
		for (int j = i + 1; j <= n; ++ j)
			if (a[j] == a[i] && f[j] == f[i])
			{
				next[i] = j;
				break;	
			}
	for (int i = 1; i <= n + 1; ++ i)
		for (int j = 0; j < i; ++ j)
		{
			if (next[j] && next[j] < i)	continue;
			if (a[j] > a[i] && f[j] + 1 == f[i])	ans[i] += ans[j];	
		}
	printf("%d %d\n", f[n + 1] - 1, ans[n + 1]);
}

int main()
{
	freopen("buylow.in", "r", stdin);
	freopen("buylow.out", "w", stdout);
	init();
	doit();
	return 0;
}



其实在读题的时候就应该考虑到了,这个题的答案的解可能非常大,需要高精度……


那么加上高精度吧……

Executing...
   Test 1: TEST OK [0.014 secs, 5384 KB]
   Test 2: TEST OK [0.011 secs, 5384 KB]
   Test 3: TEST OK [0.016 secs, 5384 KB]
   Test 4: TEST OK [0.005 secs, 5384 KB]
   Test 5: TEST OK [0.014 secs, 5384 KB]
   Test 6: TEST OK [0.035 secs, 5384 KB]
   Test 7: TEST OK [0.030 secs, 5384 KB]
   Test 8: TEST OK [0.008 secs, 5384 KB]
   Test 9: TEST OK [0.076 secs, 5384 KB]
   Test 10: TEST OK [0.324 secs, 5384 KB]

All tests OK.

以上是不压位高精度。


结果压位后……速度没啥提升

Executing...
   Test 1: TEST OK [0.005 secs, 5384 KB]
   Test 2: TEST OK [0.005 secs, 5384 KB]
   Test 3: TEST OK [0.003 secs, 5384 KB]
   Test 4: TEST OK [0.014 secs, 5384 KB]
   Test 5: TEST OK [0.008 secs, 5384 KB]
   Test 6: TEST OK [0.016 secs, 5384 KB]
   Test 7: TEST OK [0.027 secs, 5384 KB]
   Test 8: TEST OK [0.008 secs, 5384 KB]
   Test 9: TEST OK [0.073 secs, 5384 KB]
   Test 10: TEST OK [0.302 secs, 5384 KB]

All tests OK.
运算量太小,只是常数上的提升。

/*
TASK:buylow
LANG:C++
*/

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
using namespace std;

const int max_n = 5000 + 10;
int n;
int a[max_n]={0x7fffffff};

void init()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; ++ i)	scanf("%d", &a[i]);
}
const int modbuff = 1000;
struct bigint
{
	int a[100];
	bigint(int k)
	{
		memset(a, 0, sizeof(a));
		while (k)
		{
			a[++a[0]] = k % modbuff;
			k /= modbuff;
		}
	}
	bigint()
	{
		memset(a, 0, sizeof(a));	
	}
	void pg()
	{
		cout<<a[a[0]];
		for (int i = a[0] - 1; i >= 1; -- i)
		{
			if (a[i] > 99)	{cout<<a[i];continue;}
			if (a[i] > 9)	{cout<<0<<a[i];continue;}
			if (a[i])	{cout<<"00"<<a[i];continue;}
			cout<<"000";
		}
		cout<<endl;
	}

}ans[max_n]={bigint(1)};

bigint operator + (bigint A, bigint B)
{
	bigint C;
	C.a[0] = max(A.a[0], B.a[0]);
	for (int i = 1; i <= C.a[0]; ++ i)
	{
		C.a[i] += A.a[i] + B.a[i];	
		C.a[i + 1] = C.a[i] / modbuff;
		C.a[i] %= modbuff;
	}
	if (C.a[C.a[0] + 1])	++ C.a[0];
	return C;
}

int f[max_n]={0}, next[max_n]={0};
void doit()
{
	a[n + 1] = -0x7fffffff;
	for (int i = 1; i <= n + 1; ++ i)
		for (int j = 0; j != i; ++ j)	
			if (a[j] > a[i] && f[j] + 1 > f[i])	f[i] = f[j] + 1;
	for (int i = 1; i <= n; ++ i)
		for (int j = i + 1; j <= n; ++ j)
			if (a[j] == a[i] && f[j] == f[i])
			{
				next[i] = j;
				break;	
			}
	for (int i = 1; i <= n + 1; ++ i)
		for (int j = 0; j < i; ++ j)
		{
			if (next[j] && next[j] < i)	continue;
			if (a[j] > a[i] && f[j] + 1 == f[i])	ans[i] =ans[i] +  ans[j];	
		}
	printf("%d ", f[n + 1] - 1);
	ans[n + 1].pg();
}

int main()
{
	
	freopen("buylow.in", "r", stdin);
	freopen("buylow.out", "w", stdout);
	init();
	doit();
	return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值