数组切分
题解
法一:dfs暴力 O(n!) 可过30%
#include <iostream>
using namespace std;
typedef long long LL;
const int N = 10005;
const LL MOD = 1000000007;
int n;
LL ans;
int a[N];
bool vis[N];
void dfs(int idx) {
if(idx >= n) {
ans = (ans + 1) % MOD;
return;
}
for(int i = idx; i <= n; ++i) {//左闭右闭
int minn = N, maxn = 0;
for(int j = idx; j <= i; ++j) {
vis[a[j]] = 1;
minn = min(minn, a[j]);
maxn = max(maxn, a[j]);
}
bool f = 0;
for(int j = minn + 1; j < maxn; ++j) {
if(!vis[j]) {
f = 1;
break;
}
}
for(int j = minn; j <= maxn; ++j)
vis[j] = 0;//复位
if(!f) {
dfs(i + 1);
}
}
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
}
dfs(1);
printf("%lld", ans % MOD);
return 0;
}
法二:动态规划
f(i):只考虑前i个数的切分方案数
f(i) = f(i - 1) + f(i - 2) + ... + f(1) (当且仅当区间[j, i]合法)
#include <iostream>
using namespace std;
typedef long long LL;
const int N = 10005;
const LL MOD = 1000000007;
int a[N];
LL f[N];//只考虑到第i个数的切分方案数的集合 一定要开LL
int main() {
int n;
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
f[0] = 1;
f[1] = 1;
for(int i = 2; i <= n; ++i) {
int maxn = a[i], minn = a[i];
for(int j = i; j > 0; --j) {
maxn = max(maxn, a[j]);
minn = min(minn, a[j]);
if(maxn - minn == i - j) {
f[i] = (f[i] + f[j - 1]) % MOD;
}
}
}
printf("%d", f[n] % MOD);
return 0;
}
注意点
当遇到MOD时,基本都要开long long
对数器检验
#include <iostream>
#include <cmath>
#include <ctime>
#include <cstring>
using namespace std;
typedef long long LL;
const int N = 10005;
const LL MOD = 1000000007;
int n;
LL ans = 0;
int a[N];
int f[N];//只考虑到第i个数的切分方案数的集合
bool vis[N];
//动态规划解
void dp() {
f[0] = 1;
f[1] = 1;
for(int i = 2; i <= n; ++i) {
int maxn = a[i], minn = a[i];
for(int j = i; j > 0; --j) {
maxn = max(maxn, a[j]);
minn = min(minn, a[j]);
if(maxn - minn == i - j) {
f[i] = (f[i] + f[j - 1]) % MOD;
}
}
}
}
//dfs暴力解
void dfs(int idx) {
if(idx >= n) {
ans = (ans + 1) % MOD;
return;
}
for(int i = idx; i <= n; ++i) {//左闭右闭
int minn = N, maxn = 0;
for(int j = idx; j <= i; ++j) {
vis[a[j]] = 1;
minn = min(minn, a[j]);
maxn = max(maxn, a[j]);
}
bool f = 0;
for(int j = minn + 1; j < maxn; ++j) {
if(!vis[j]) {
f = 1;
break;
}
}
for(int j = minn; j <= maxn; ++j)
vis[j] = 0;//复位
if(!f) {
dfs(i + 1);
}
}
}
//对数器检验
int main() {
n = 35;
srand(time(NULL));
for(int k = 1; k <= 5; ++k) {
ans = 0;
memset(f, 0, sizeof(f));
//先排序,后对随机位置交换 => 打乱
for(int i = 1; i <= n; ++i) {
a[i] = i;
}
for(int i = 1; i <= 5; ++i) {
int t1 = (rand() % n) + 1;
int t2 = (rand() % n) + 1;
int temp = a[t1];
a[t1] = a[t2];
a[t2] = temp;
}
dfs(1);
dp();
if(ans == f[n])
printf("ok\n");
else
printf("error:%d %d\n", ans, f[n]);
}
return 0;
}