[Luogu1846] [NOIP2012模拟10.22] 游戏 [dp]

link

a i = a i − 1 , b i = b i − 1 \mathfrak{a_i=a_i-1,b_i=b_i-1} ai=ai1,bi=bi1

显然数比较少的那一列,每个数都应该属于不同的被操作数集合
考虑上面那一列怎么做。

a b \mathfrak{ab} ab
c d \mathfrak{cd} cd
不拆, ( a + b ) ( c + d ) = a c + b c + a d + b d \mathfrak{(a+b)(c+d)=ac+bc+ad+bd} (a+b)(c+d)=ac+bc+ad+bd
拆, a c + b d \mathfrak{ac+bd} ac+bd
⋯ \cdots

可以发现不拆总会比拆答案要大

要用 D P \mathcal{DP} DP相信很容易看出来(
一种自然的思路是考虑把数选入集合。
如果两个序列数的个数相等,当然一个对着一个放进去就是最后的答案
否则就把长的那一列提出来考虑。
也就是考虑长的那一列的第 i \mathfrak{i} i个数是否选入第 j \mathfrak{j} j个集合。
从集合中选入元素,那么单个集合可以分为选一个或者选多个。
用状态 f ( i , j ) \mathfrak{f(i,j)} f(i,j)表示选到长的一列第 i \mathfrak{i} i个数,已经有 j \mathfrak{j} j个集合,此时的最小答案。
于是 f ( i , j ) = m i n { f ( i − 1 , j − 1 ) , f ( i − 1 , j ) , f ( i , j − 1 ) } + a i b j \mathfrak{f(i,j)=min\{f(i-1,j-1),f(i-1,j),f(i,j-1)\}+a_ib_j} f(i,j)=min{f(i1,j1),f(i1,j),f(i,j1)}+aibj
其中, f ( i − 1 , j − 1 ) \mathfrak{f(i-1,j-1)} f(i1,j1)转移过来代表集合 j \mathfrak{j} j里面就只有 i \mathfrak{i} i一个数。
而从 f ( i − 1 , j ) , f ( i , j − 1 ) \mathfrak{f(i-1,j),f(i,j-1)} f(i1,j),f(i,j1) j \mathfrak{j} j里面有多个数。
其中 f ( i − 1 , j ) \mathfrak{f(i-1,j)} f(i1,j)就是集合 j + 1 \mathfrak{j+1} j+1还没确定,而 f ( i , j − 1 ) \mathfrak{f(i,j-1)} f(i,j1)是确定了集合 j \mathfrak{j} j
这算是把朴素方程 f ( i , j ) = m i n { f ( x , j − 1 ) + b j ∑ k = x + 1 i a k } \mathfrak{f(i,j)=min\{f(x,j-1)+b_j\sum\limits_{k=x+1}^i a_k}\} f(i,j)=min{f(x,j1)+bjk=x+1iak}进行了一种懒处理

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
int N,M;
long long A[2005]={},B[2005]={};
long long F[2005][2005]={};
int main()
{
	cin>>N>>M;
	for(int i=1;i<=N;++i)cin>>A[i],--A[i];
	for(int i=1;i<=M;++i)cin>>B[i],--B[i];
	for(int i=0;i<=N;++i)
	for(int j=0;j<=M;++j)
	F[i][j]=2147483647147483647ll;
	F[0][0]=0;
	for(int i=1;i<=N;++i)
	for(int j=1;j<=M;++j)
	F[i][j]=min(min(F[i][j-1],F[i-1][j]),F[i-1][j-1])+A[i]*B[j];
	cout<<F[N][M];
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值