zoukankan      html  css  js  c++  java
  • 【构造】【dp】POJ1722

    题面

    给定一个n个正整数的序列{(a_n)},在这个序列上我们可以执行收缩操作。一次收缩操作可指定一个i,使(a_i)-(a_{i+1})替换(a_i),(a_{i-1})。对于n个整数的序列,我们可以执行n-1个不同的收缩操作,每个收缩操作都会产生一个新的长度为n-1序列。现给定序列{(a_n)}和目标数t,求一个n-1操作序列,使最后得到t。1<=n,(a_i)<=100,1<=t<=1000

    链接:http://poj.org/problem?id=1722

    思路

    设最终答案为ans,ans一定会加上(a_1)减去(a_2)。在一个操作序列进行完操作后,若(a_k)最终为减号时,(a_{k+1})最终为加号时,对k进行操作,把(a_{k+1})先减到(a_k)上 ,因为后面a_k一定会减,所以(a_{k+1})最终就是加号了。对所有这样的一对数先进行操作,最后会只剩下为加号的(a_1),和一堆最终为减号的(a_k),这时候我们一直对1进行操作,最后(a_k)就都会是减号。综上只有(a_1),(a_2)的符号是固定的,(a_k)的符号无论加减都至少有一种操作序列满足要求。所以我们不有考虑不好维护的每一次操作的瞬时状态,而是考虑容易维护的最终状态,再结合前面的过程求得答案。具体就是把题目划为两个部分,一部分设(f_i,_j)来表示操作到a_i时,能否使结果为j,转移方程:

    (f_i,_j=f_{i-1},_{j+a_i}|f_{i-1},_{j-a_i})

    并保存路径即(a_i)前面的加减号。一部分由加减号来构造一个符合要求的操作序列。

    代码

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    const int N=110,M=1e4+10;
    short path[N][M<<1],a[N],f[N][M<<1],an[N];
    void dfs(int i,int j)
    {
    	if(i==2) return;
    	if(path[i][j]) dfs(i-1,j+a[i]);
    	else dfs(i-1,j-a[i]);
    	an[i]=path[i][j];
    }
    int main()
    {
    //	freopen("data.in","r",stdin);
    //	freopen("data.out","w",stdout);
    	int n,k,last,cnt=1;
    	scanf("%d%d",&n,&k);
    	if(n==1) return 0;
    	if(n==2)
    	{
    		printf("1
    ");
    		return 0;
    	}
    	for(int i=1;i<=n;i++) cin>>a[i];
    	f[1][M+a[1]]=f[2][M+a[1]-a[2]]=1;
    	for(int i=3;i<=n;i++)
    	{
    		for(int j=1;j<(M<<1);j++)
    		{
    			if(j-a[i]>0&&f[i-1][j-a[i]]) f[i][j]=1,path[i][j]=0;
    			if(!f[i][j]&&j+a[i]<(M<<1)&&f[i-1][j+a[i]]) f[i][j]=1,path[i][j]=1;
    			if(!f[i][j]) path[i][j]=-1;
    		}
    	}
    	dfs(n,M+k);
    	last=2;int in=0;
    	for(int i=3;i<=n;i++)
    	{
    		if(!an[i]) printf("%d
    ",last),in++;
    		else last=i-in,cnt++;
    	}
    	for(int i=1;i<=cnt;i++) printf("1
    ");
    	return 0;
    }
    
    
  • 相关阅读:
    jQuery--.wrap()方法
    ECharts学习(4)--仪表盘
    ECharts学习(3)--toolbox(工具栏)
    jQuery之核心API
    STM32片上Flash内存映射、页面大小、寄存器映射
    typedef struct bit0 : 1
    ***WARNING L15: MULTIPLE CALL TO SEGMENT
    C/C++ 打印文件名、行号、函数名的方法
    ISP与IAP的区别
    sprintf函数 %6.2f
  • 原文地址:https://www.cnblogs.com/flashlizard/p/10994090.html
Copyright © 2011-2022 走看看