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;
    }
    
    
  • 相关阅读:
    整个过程
    iframe 重新加载闪过白块问题
    C# 获得两日期之间所有月份(包括跨年)
    新手是个框,啥都往里装!---谨以此文致歉博友和自己的无知
    C# 和Java的foreach的不同用法
    终于鼓起勇气,辞掉了第一份工作
    Java Junit4测试功能
    自学Android的第一个小程序(小布局、button点击事件、toast弹出)
    JS--Div中数据滚动到最后一条重新从头开始滚动
    RelativeLayout与LinearLayout的区别
  • 原文地址:https://www.cnblogs.com/LSlzf/p/10659186.html
Copyright © 2011-2022 走看看