zoukankan      html  css  js  c++  java
  • poj1722 SUBTRACT【线性DP】

    SUBTRACT
    Time Limit: 1000MS   Memory Limit: 10000K
    Total Submissions: 2037   Accepted: 901   Special Judge

    Description

    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.

    Input

    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

    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 ithcontraction to be applied. 
    You can assume that at least one such sequence of contractions will exist for a given input. 

    Sample Input

    5 4
    12
    10
    4
    3
    5
    

    Sample Output

    2
    3
    2
    1

    Source

    题意:

    给N个数,每次选定一个i,用a[i] - a[i+1]的结果取代a[i]和a[i+1]。操作N-1次之后,就只剩下1个数。问如何选择,可以使这个数恰好是T

    思路:

    我们可以发现,这个序列每次用减来取代的话,其实就是在n个数之前加上正负,然后让他们都加起来的和结果是T。

    而且a[1]一定是正,a[2]一定是负。

    于是我们用dp[i][j]来表示第i个数得到分数j时的符号,1表示是加,-1表示是减,0表示没有扩展到。【我怎样才能聪明地想到要这样来表示呢】

    我们枚举i,j,判断上一个状态i-1有没有扩展到当前分数j。如果有,那么dp[i][j + a[i]] = 1, dp[i][j - a[i]] = -1

    然后我们从dp[n][t]开始倒推出每一个元素之前的符号。ans[i]表示的就是a[i]前的符号。

    那么方案该怎么输出?

    先去处理所有的加号,相当于把所有的加号都挪去了原来a3的位置,这样最后处理减号的时候,减a2就可以负负得正了。

    然后处理减号,把所有的减号都挪到了原来a2的位置,给a1来减。

     1 //#include <bits/stdc++.h>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<algorithm>
     5 #include<stdio.h>
     6 #include<cstring>
     7 #include<vector>
     8 #include<map>
     9 #include<set>
    10 
    11 #define inf 0x3f3f3f3f
    12 using namespace std;
    13 typedef long long LL;
    14 
    15 int n, t;
    16 int a[105];
    17 int dp[105][20010], ans[105];
    18 const int base = 10005;
    19 
    20 int main()
    21 {
    22     while(scanf("%d%d", &n, &t) != EOF){
    23         for(int i = 1; i <= n; i++){
    24             scanf("%d", &a[i]);
    25         }
    26         memset(dp, 0, sizeof(dp));
    27         dp[1][a[1] + base] = 1;
    28         dp[2][a[1] - a[2] + base] = -1;
    29         for(int i = 3; i <= n; i++){
    30             for(int j = -10000 + base; j <= 10000 + base; j++){
    31                 if(dp[i - 1][j] != 0){
    32                     dp[i][j + a[i]] = 1;
    33                     dp[i][j - a[i]] = -1;
    34                 }
    35             }
    36         }
    37 
    38         int want = t + base;
    39         for(int i = n; i >= 2; i--){
    40             ans[i] = dp[i][want];
    41             if(ans[i] == 1){
    42                 want -= a[i];
    43             }
    44             else if(ans[i] == -1){
    45                 want += a[i];
    46             }
    47         }
    48 
    49         int cnt = 0;
    50         for(int i = 2; i <= n; i++){
    51             if(ans[i] == 1){
    52                 printf("%d
    ", i - cnt - 1);
    53                 cnt++;
    54             }
    55         }
    56         for(int i = 2; i <= n; i++){
    57             if(ans[i] == -1){
    58                 printf("1
    ");
    59             }
    60         }
    61     }
    62     return 0;
    63 }
  • 相关阅读:
    叙旧
    注册表的基本操作(.Net)
    如何自己实现 JavaScript 的 new 操作符?
    装饰者模式和TypeScript装饰器
    彻底弄懂GMT、UTC、时区和夏令时
    Javascript 中 cookie 操作方式
    javascript实例教程:使用canvas技术模仿echarts柱状图
    实现memcached客户端:TCP、连接池、一致性哈希、自定义协议
    Linux终端快速检测网站是否宕机的6个方法
    爬虫是什么吗?你知道爬虫的爬取流程吗?
  • 原文地址:https://www.cnblogs.com/wyboooo/p/9775701.html
Copyright © 2011-2022 走看看