【BZOJ3072】[Pa2012]Two Cakes【DP】

【题目链接】

题解:

很容易想到O(n^2)DP的做法。

(1)A[i] == B[j],dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + 1

(2)A[i] != B[j],dp[i][j] = dp[i - t + 1][j - t + 1] + t,t表示最长的一段不相等的数的长度

发现如果连续的一段内要填写的两个数都不相同,那么一定是贪心转移的,即只有数字相同的地方需要DP。

如何快速找到t?

考虑全排列每个数字只出现了一次,可以得出相同数字的位置差。然后又注意到位置差一定和x, y的位置差相同。

那么我们记录出每个位置差(一共有2n个)出现的数的下标,然后二分查找。

另一个问题是DP数组开不下,注意到只有数字相同的地方需要DP,那么我们只记录两个数字相同时候的DP值即可,然后记忆化搜索。

即dp[i]表示,考虑第一个串里的前i个数字,并且两只手都遇到了A[i],的最小代价。

然后另一个下标用搜索去搞。

复杂度:

时间复杂度:状态数O(n),每次转移最坏O(logn),总复杂度O(nlogn)。

空间复杂度:O(n)

GET:

要注意到什么状态影响决策,不影响决策的状态单独处理。

/* Telekinetic Forest Guard */
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <iostream>

using namespace std;

const int maxn = 1000005;

int n, A[maxn], B[maxn], pos[maxn], dp[maxn];

vector<int> dif[maxn << 1];

inline int iread() {
	int f = 1, x = 0; char ch = getchar();
	for(; ch < '0' || ch > '9'; ch = getchar()) f = ch == '-' ? -1 : 1;
	for(; ch >= '0' && ch <= '9'; ch = getchar()) x =  x * 10 + ch - '0';
	return f * x;
}

inline int find(int id, int x) {
	int l = 0, r = dif[id].size() - 1, res = -1;
	while(l <= r) {
		int mid = l + r >> 1;
		if(dif[id][mid] <= x) res = mid, l = mid + 1;
		else r = mid - 1;
	}
	return ~res ? dif[id][res] : 0;
}

inline int dfs(int x, int y) {
	if(!x || !y) return x + y;
	if(A[x] == B[y]) return dp[x] ? dp[x] : dp[x] = min(dfs(x - 1, y), dfs(x, y - 1)) + 1;
	int t = find(x - y + n, x);
	return t ? dfs(t, y - x + t) + x - t : max(x, y);
}

int main() {
	n = iread();
	for(int i = 1; i <= n; i++) A[i] = iread();
	for(int i = 1; i <= n; i++) pos[B[i] = iread()] = i;

	for(int i = 1; i <= n; i++) {
		int d = i - pos[A[i]] + n;
		dif[d].push_back(i);
	}

	printf("%d\n", dfs(n, n));
	return 0;
}

附暴力

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn = 1000005;

int n, A[maxn], B[maxn], ans;

inline int iread() {
	int f = 1, x = 0; char ch = getchar();
	for(; ch < '0' || ch > '9'; ch = getchar()) f = ch == '-' ? -1 : 1;
	for(; ch >= '0' && ch <= '9'; ch = getchar()) x =  x * 10 + ch - '0';
	return f * x;
}

inline void dfs(int x, int y, int d) {
	if(x == n + 1 && y == n + 1) {
		ans = min(ans, d);
		return;
	}
	if(x == n + 1) dfs(x, y + 1, d + 1);
	else if(y == n + 1) dfs(x + 1, y, d + 1);
	else {
		if(A[x] != B[y]) dfs(x + 1, y + 1, d + 1);
		else {
			dfs(x + 1, y, d + 1);
			dfs(x, y + 1, d + 1);
		}
	}
}

int main() {
	freopen("1.in", "r", stdin);
	freopen("1.ans", "w", stdout);
	n = iread();
	for(int i = 1; i <= n; i++) A[i] = iread();
	for(int i = 1; i <= n; i++) B[i] = iread();

	ans = n << 1;
	dfs(1, 1, 0);

	printf("%d\n", ans);
	return 0;
}

mk

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <ctime>
#include <cstdlib>

using namespace std;

typedef long long LL;

const int maxn = 1000005;

int n, vis[maxn];

inline int rd(int x) {
	return (LL)rand() * rand() % x + 1;
}

int main() {
	freopen("1.in", "w", stdout);
	srand(time(0));

	int n = 1000;
	printf("%d\n", n);

	for(int i = 1; i <= n; i++) {
		int x = rd(n);
		for(; vis[x] == 1; x = rd(n));
		vis[x] = 1;
		printf("%d ", x);
	}
	printf("\n");

	for(int i = 1; i <= n; i++) {
		int x = rd(n);
		for(; vis[x] == 2; x = rd(n));
		vis[x] = 2;
		printf("%d ", x);
	}
	printf("\n");

	return 0;
}
时间: 2024-10-09 23:46:40

【BZOJ3072】[Pa2012]Two Cakes【DP】的相关文章

【BZOJ3502/2288】PA2012 Tanie linie/【POJ Challenge】生日礼物 堆+链表(模拟费用流)

[BZOJ3502]PA2012 Tanie linie Description n个数字,求不相交的总和最大的最多k个连续子序列. 1<= k<= N<= 1000000. Sample Input 5 2 7 -3 4 -9 5 Sample Output 13 题解:跟1150和2151差不多. 我们先做一些预处理,因为连续的正数和连续的负数一定是要么都选要么都不选,所以可以将它们合并成一个数,同时区间中的零以及左右两端的负数没有意义,可以将它们删掉.然后我们得到的序列就变成:正-

POJ 2923 【01背包+状态压缩/状压DP】

题目链接 Emma and Eric are moving to their new house they bought after returning from their honeymoon. Fortunately, they have a few friends helping them relocate. To move the furniture, they only have two compact cars, which complicates everything a bit.

Vijos 1523 贪吃的九头龙 【树形DP】

贪吃的九头龙 背景 安徽省芜湖市第二十七中学测试题 NOI 2002 贪吃的九头龙(dragon) Description:OfficialData:OfficialProgram:Converted by JackDavid127 描述 传说中的九头龙是一种特别贪吃的动物.虽然名字叫"九头龙",但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于九,当然也会有旧头因衰老而自己脱落. 有一天,有M个脑袋的九头龙看到一棵长有N个果子的果树,喜出望外,

POJ - 3286 - How many 0&#39;s? 【数位DP】

How many 0's? Time Limit: 1000MS   Memory Limit: 65536KB   64bit IO Format: %I64d & %I64u Description A Benedict monk No.16 writes down the decimal representations of all natural numbers between and including m and n, m ≤ n. How many 0's will he writ

hdoj 2391 Filthy Rich 【DP】

题目大意:有个二维数组,你从(0,0)出发,最终到(n,m), 在这个二维数组中,每个位置dp[i][j]都有一定量的黄金,你可以拾取,问你最多能失去多少,并且,你的方向有下,右, 斜向下三个方向: 策略:就是每一个都加上它的上方向与左方向的最大值,这样到最后就是最大值.详情见代码 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2391 代码: #include<stdio.h> #include<string.h> int dp[1

HDOJ1176 免费馅饼 【DP】+【经典数塔】

免费馅饼 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 23986    Accepted Submission(s): 8093 Problem Description 都说天上不会掉馅饼,但有一天gameboy正走在回家的小径上,忽然天上掉下大把大把的馅饼.说来gameboy的人品实在是太好了,这馅饼别处都不掉,就掉落在他身旁的1

【概率DP】poj2096Collecting Bugs

/* 水水的概率DP: 定义数组dp(i, j)表示在j个子系统中有i种bug..要达到目标的期望::: 其中,dp[n][s]为0,因为已经是目标状态,,dp[0][0]为最终的结果:: ---- 分析,dp[i][j]可以达到下面的4种状态: dp[i][j] 发现一个bug属于已经找到的i种bug和j个子系统中的期望 dp[i+1][j] 发现一个bug属于新的一种bug,但属于已经找到的j种子系统的期望 dp[i][j+1] 发现一个bug属于已经找到的i种bug,但属于新的子系统的期望

nyoj 325 zb的生日 【DP】||【DFS】

两种方法: 第一种:将总数一半当做背包,用总数-2*最多能装的数目就是所求: 第二种:深搜: zb的生日 时间限制:3000 ms  |  内存限制:65535 KB 难度:2 描述 今天是阴历七月初五,acm队员zb的生日.zb正在和C小加.never在武汉集训.他想给这两位兄弟买点什么庆祝生日,经过调查,zb发现C小加和never都很喜欢吃西瓜,而且一吃就是一堆的那种,zb立刻下定决心买了一堆西瓜.当他准备把西瓜送给C小加和never的时候,遇到了一个难题,never和C小加不在一块住,只能

HDOJ4540 威威猫系列故事——打地鼠 【DP】

威威猫系列故事--打地鼠 Time Limit: 300/100 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 1445    Accepted Submission(s): 713 Problem Description 威威猫最近不务正业,每天沉迷于游戏"打地鼠". 每当朋友们劝他别太着迷游戏,应该好好工作的时候,他总是说,我是威威猫,猫打老鼠就是我的工作! 无话