第一问:显然是最长下降子序列
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;
}