zoukankan      html  css  js  c++  java
  • [luoguP1415] 拆分数列(DP)

    传送门

    t(i,j)表示下标从i到j的数

    d[i]表示以i结尾的最小的数的下标

    d[i]=max(j) (1<=j<=i && t(d[j-1],j-1)<t(j,i))

    这样从1到n一遍DP可以求出末尾最小的数

    f[i]表示以i开头的最大的数的下标

    f[i]=max(j) (i<=j<=n && t(i,j)<t(j+1,d[j+1]))

    边界为f[d[n]]=n

    这样从d[n]-1到1一遍DP可以求出开头最大的数,第二个最大的数。。。

    注意前导0的情况

    #include <cstdio>
    #include <cstring>
    #define N 1001
    
    int n;
    char s[N];
    int d[N], f[N];
    //d[i]表示以i结尾的数,满足条件的最小数 
    //f[i]表示以i开头的数,满足条件的最大数 
    //s[i][j]表示从i到j的数是多少 
    
    inline int cmp(int x1, int y1, int x2, int y2)
    {
    	int i, j;
    	while(s[x1] == '0') x1++;
    	while(s[x2] == '0') x2++;
    	if(y1 - x1 == y2 - x2)
    	{
    		for(i = x1, j = x2; i <= y1; i++, j++)
    		{
    			if(s[i] > s[j]) return 1;
    			if(s[i] < s[j]) return 2;
    		}
    		return 0;	
    	}
    	if(y1 - x1 > y2 - x2) return 1;
    	if(y1 - x1 < y2 - x2) return 2;
    }
    
    int main()
    {
    	int i, j, k;
    	scanf("%s", s + 1);
    	n = strlen(s + 1);
    	for(i = 1; i <= n; i++)
    		for(j = i; j >= 1; j--)
    			if(cmp(j, i, d[j - 1], j - 1) == 1)
    			{
    				d[i] = j;
    				break;
    			}
    	while(s[d[n] - 1] == '0') d[n]--;
    	for(i = d[n]; i <= n; i++) f[i] = n;
    	for(i = d[n] - 1; i >= 1; i--)
    	{
    		k = n;
    		for(j = i; j <= n; j++)
    			if(cmp(i, j, j + 1, f[j + 1]) == 2)
    				k = j;
    		f[i] = k;
    	}
    	if(cmp(1, n, d[n], n) == 0)
    	{
    		printf("%s", s + 1);
    		return 0;
    	}
    	j = 1;
    	while(j <= n)
    	{
    		for(i = j; i <= f[j]; i++)
    			printf("%c", s[i]);
    		j = f[j] + 1;
    		if(j <= n) putchar(',');
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    2.1.7出现异常,锁自动释放
    2.1.5脏读
    2.1.4synchronized方法与锁对象
    2.1.3多个对象多个锁
    2.1.2实例变量非线程安全
    2.1.1方法内的变量为线程安全
    Linux内核开发
    fl2440 platform总线led字符设备驱动
    fl2440字符设备led驱动
    cdev结构体及其相关函数
  • 原文地址:https://www.cnblogs.com/zhenghaotian/p/7609514.html
Copyright © 2011-2022 走看看