【洛谷P1415】拆分数列【dp】

题目大意:

题目链接:https://www.luogu.org/problemnew/show/P1415
给出一列数字,需要你添加任意多个逗号将其拆成若干个严格递增的数。如果有多组解,则输出使得最后一个数最小的同时,字典序最大的解(即先要满足最后一个数最小;如果有多组解,则使得第一个数尽量大;如果仍有多组解,则使得第二个数尽量大,依次类推……)。


思路:

由于要先把最后一位尽量小,考虑先求出最后一位的最小答案。
f[i]f[i]表示在满足前ii位的划分单调递增时,以第ii位为末,且这一次的划分的值尽量小的时候划分的首位。
简单来说,就是找到一个jj满足在jj开始划分可以满足单调递增且ji\overline{j\sim i}尽量小的方案数。
显然只需要让jj尽量大就可以了。就倒序枚举jj,如果f[j1]j1<ji\overline{f[j-1]\sim j-1}<\overline{j\sim i}就让f[i]=jf[i]=j
其中xy\overline{x\sim y} 可以预处理搞定。
接下来求出满足前面尽量大的答案。
g[i]g[i]表示在满足后ii位的划分满足单调递增时,以第ii位为首,且这一次的划分的值尽量大的时候划分的末位。
显然初始化d[f[n]]=nd[f[n]]=n
推方程思路和ff基本一样。
注意处理前导0。可以用sum[x][y]sum[x][y]表示xy\overline{x\sim y}的前导0个数。
这样的时间复杂度就是O(n3)O(n^3)的。实际上跑起来会小得多。


代码:

#include <cstdio>
#include <string>
#include <iostream>
using namespace std;

const int N=510;
int n,a[N],f[N],g[N],sum[N][N];
string t[N][N];

bool check(int S1,int T1,int S2,int T2)
{
	if (T1-S1-sum[S1][T1]<T2-S2-sum[S2][T2]) return 1;
	if (T1-S1-sum[S1][T1]>T2-S2-sum[S2][T2]) return 0;
	string s1=t[S1+sum[S1][T1]][T1],s2=t[S2+sum[S2][T2]][T2];
	for (int i=0;i<min(s1.size(),s2.size());i++)
	{
		if (s1[i]<s2[i]) return 1;
		if (s1[i]>s2[i]) return 0;
	}
	return 0;
}

void dp1()
{
	f[1]=1;
	for (int i=2;i<=n;i++)
		for (int j=i;j>=1;j--)
			if (check(f[j-1],j-1,j,i))
			{
				f[i]=j;
				break;
			}
}

void dp2()
{
	g[f[n]]=n;
	int k=0;
	for (int i=f[n]-1;!a[i]&&i;i--) g[i]=n,k++;
	for (int i=f[n]-1-k;i>=1;i--)
		for (int j=f[n]-1;j>=i;j--)
			if (check(i,j,j+1,g[j+1]))
			{
				g[i]=j;
				break;
			}
	int i;
}

int main()
{
	while (scanf("%1d",&a[++n])==1)
		for (int i=1;i<=n;i++)
		{
			t[i][n]=t[i][n-1]+(char)(a[n]+48);
			if (sum[i][n-1]==max(n-i,0)&&!a[n]) sum[i][n]=sum[i][n-1]+1;
				else sum[i][n]=sum[i][n-1];
		}
	n--;
	dp1();
	dp2();
	int j=g[1];
	for (int i=1;i<=n;i++)
	{
		printf("%d",a[i]);
		if (i==j&&i!=n)
		{
			j=g[i+1];
			putchar(',');
		}
	}
	return 0;
}

这道题思路还是不难,但是敲了我3h3h。。。恐怖如斯
话说这道题有要求O(nlogn)O(n\log n)的加强版\to P2282[HNOI2003]历史年份,好像是用hash+hash+二分判断两个子串的大小,线段树维护f的最大值。。。orz

posted @ 2019-04-26 22:02  全OI最菜  阅读(135)  评论(0编辑  收藏  举报