zoukankan      html  css  js  c++  java
  • [POJ1772] Substract

    问题描述

    We are given a sequence of N positive integers a = [a1, a2, ..., aN] on which we can perform contraction operations.

    One contraction operation consists of replacing adjacent elements ai and ai+1 by their difference ai-ai+1. For a sequence of N integers, we can perform exactly N-1 different contraction operations, each of which results in a new (N-1) element sequence.Precisely, let con(a,i) denote the (N-1) element sequence obtained from [a1, a2, ..., aN] by replacing the elements ai and ai+1 by a single integer ai-ai+1:

    con(a,i) = [a1, ..., ai-1, ai-ai+1, ai+2, ..., aN]

    Applying N-1 contractions to any given sequence of N integers obviously yields a single integer.

    For example, applying contractions 2, 3, 2 and 1 in that order to the sequence [12,10,4,3,5] yields 4, since :

    con([12,10,4,3,5],2) = [12,6,3,5]
    
    con([12,6,3,5]   ,3) = [12,6,-2]
    
    con([12,6,-2]    ,2) = [12,8]
    
    con([12,8]       ,1) = [4]
    

    Given a sequence a1, a2, ..., aN and a target number T, the problem is to find a sequence of N-1 contractions that applied to the original sequence yields T.

    输入格式

    The first line of the input contains two integers separated by blank character : the integer N, 1 <= N <= 100, the number of integers in the original sequence, and the target integer T, -10000 <= T <= 10000. The following N lines contain the starting sequence : for each i, 1 <= i <= N, the (i+1)st line of the input file contains integer ai, 1 <= ai <= 100.

    输出格式

    Output should contain N-1 lines, describing a sequence of contractions that transforms the original sequence into a single element sequence containing only number T. The ith line of the output file should contain a single integer denoting the ith contraction to be applied. You can assume that at least one such sequence of contractions will exist for a given input.

    样例输入

    5 4
    12
    10
    4
    3
    5

    样例输出

    2
    3
    2
    1

    题目大意

    给定一个序列a,每次可以选择两个数a[i]和a[i+1],从序列中将这两个数替换为一个数a[i]-a[i+1]。求最少的操作方案使最后剩下的数为给定的t。

    题解

    假设我们有三个数i,j,k,如果我们首先将j和k合并,得到了i和j-k。接下来把剩下两个数合并,最后的结果为i-(j-k)=i-j+k。换一种方式,首先合并i和j,得到i-j和k,再合并两个数,得到的最后结果为i-j-k。容易发现,最后的结果其实是由序列中的数通过加和减的操作得来的。那么问题就转化为对一个序列加入加号和减号,使其最后计算出的结果为t。由于最后要求输出方案,我们可以利用动态规划来完成。设(f[i][j])表示在第i个数、前面计算结果为j时第i个数为加还是减。那么状态转移方程为:

    [f[i][j+a[i]]=1,f[i][j-a[i]]=0 ]

    其中1表示为加号,0表示为减号。那么我们怎么推出方案呢?已知最后的结果为t,那么可以用倒推法,一步一步地推出方案。假设当前结果为s,如果(f[i][s])为1,说明这个数取正,同时使s减去a[i]。反之取负,同时s加上a[i]。如此往复。但怎么推出是第几个呢?我们不妨这样做:首先把所有加号处理完,然后一起输出减号。因为如果最后只剩减号的话,可以一直输出1而没有对位置的影响。那么现在考虑加号的决策。如果一个值取得为加号,那么在此之前这个数一定是被合并过的。记前面进行过的操作次数为cnt。那么这个数的位置一共被向前推移了cnt次。但按照输出规则,应当输出它的前一个数(前一个数和该数合并)。

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define N 102
    #define M 10002
    using namespace std;
    const int T=10000;
    int n,t,i,j,a[N],f[N][M*2],opt[N];
    int main()
    {
    	cin>>n>>t;
    	for(i=1;i<=n;i++) cin>>a[i];
    	memset(f,-1,sizeof(f));
    	f[1][a[1]+T]=1;
    	f[2][a[1]-a[2]+T]=0;
    	for(i=3;i<=n;i++){
    		for(j=0;j<=2*T;j++){
    			if(f[i-1][j]!=-1){
    				f[i][j+a[i]]=1;
    				f[i][j-a[i]]=0;
    			}
    		}
    	}
    	j=t+T;
    	for(i=n;i>=1;i--){
    		if(f[i][j]==1){
    			opt[i]=1;
    			j-=a[i];
    		}
    		else if(f[i][j]==0){
    			opt[i]=0;
    			j+=a[i];
    		}
    	}
    	int cnt=0;
    	for(i=2;i<=n;i++){
    		if(opt[i]==1){
    			cout<<i-cnt-1<<endl;
    			cnt++;
    		}
    	}
    	for(i=2;i<=n;i++){
    		if(opt[i]==0) cout<<"1"<<endl;
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    几种常用的曲线
    0188. Best Time to Buy and Sell Stock IV (H)
    0074. Search a 2D Matrix (M)
    0189. Rotate Array (E)
    0148. Sort List (M)
    0859. Buddy Strings (E)
    0316. Remove Duplicate Letters (M)
    0452. Minimum Number of Arrows to Burst Balloons (M)
    0449. Serialize and Deserialize BST (M)
    0704. Binary Search (E)
  • 原文地址:https://www.cnblogs.com/LSlzf/p/10659186.html
Copyright © 2011-2022 走看看