POJ 1722 SUBTRACT

给定一个数组a[1,2,..,n] 。定义数组第i位上的减操作:把ai和ai+1换成ai - ai+1。输入一个n位数组以及目标整数t,求一个n-1次操作序列,使得最后剩下的数等于t
最后输出依此操作的i

输入:第一行一个N,一个T,接下来N行,每行一个正整数ai
输出:依次输出被操作的位置i

首先对题目进行分析后,似乎没有什么好的思路。
从结果入手。
对于最后的得到的整数,肯定是将原数列中一些数前加上了符号,然后将数列加在一起的操作。
这样我们就避免了麻烦的数组操作。‘

这样我们将题目转换成了:
一个数列[a1, a2, ....aN],对于数组中的数,将部分正整数变为负数,使整个数组的和为t,最后输出将哪些数变为负数
其中,从原题中我们可以知道:由于第1个数前没有数,所以第1个数不可能加负数,这样我们想,假设最后剩下两个数a1, a2,由原题目我们知道,要想把这两个数化为一个整数,第二个数必须为负数。
因此,在最初,第一个数必须为正,第二个数必须为负数。

然后整理能够描述状态空间的信息:
1.一个正整数i,表示进行到了第i个数
2.标记-1或1,表示第i个数取负还是取正
3.一个整数,表示进行到第i个数时,前i个数的和

接着我们要确定的是第i个数取正还是取负,然后我们还需要前i-1一个数的和,但是我们能够注意到的是,前i-1个数的和是不确定的,对于i前的除了1,2位置的数,每一个数都有取正和取负两个操作,由于i可能很大
因此前i-1个数的和的结果也很多,所以对于i-1个数的和是不确定的,而对于第i个数取正还是取负,一共只有两个情况。
这样我们只能将前i-1个数的和作为变量,加一个维度,用来描述状态空间。
设f[i, j] = k表示到第i个数,前i个数的和为j时,第i个数的标记为k
这样问题的重点就在于如何记录路径了
对于我们的思路肯定是倒推回去
我们试着从f[][t]推回去
但是对于第一维,我们是并不确定的,
我们只能试着将i从2到n一个一个搜,但是注意的是i不能从1开始,最后我们处理1时再说原因
我们从我们的策略分析:我们可以发现,我们首先需要输出的显然是一路倒推后标记为1的i值,但是我们有一点就是我们每操作一个i,i之后的数的下标会全部减1。
因此首先我们首先要从答案一路逆推回去,同时开一个新数组,在第i个位置标记这个数是取正还是取负。
然后首先输出所有标记取正的下标,但是我们知道一个操作结束后后面的下标会变,所以我们设一个新的变量记录在某个位置之前操作了多少次,例如:我们设我们现在第i个位置,前面操作了cnt次,这样i的下标就应该因为操作而被迫变更了cnt次,但是观察样例的推断我们可以发现,在样例中,原本i = 2时,i = 2理当是正的,但是在最初我们全部将i = 2的情况标记为负了,所以这就是说,类推到所有情况,所有取正的下标,在原题i和i+1的
情况中,实际上取正的是i+1,所以对于取正的位置的下标,除了要减去cnt外,还要再减去1
最后我们讨论输出1的情况,我们相当我们吧所有取正的情况输出后,操作次数cnt,很可能(很大可能)并不到n-1,一方面是因为刚才我们没有输出1,但另一方面,存在cnt与n-1的差距不止1,这种情况说明在最后,在进行了全部的操作后,最后所有剩下的数不再进行取正操作,也就是说除了1之外全部取为了负数,例如: 1 2 3 4 5 6 ,除了1之外,2,3,4,5,6全部标成取负号,这意味着在这些操作中,所有的i全部取为1,所以我们就要输出
n-1-cnt个1,当然也可以是在所有在标记为取负的位置输出'1',但是我们上面说了因为2的符号强制取负的关系,下标除了减去cnt还要再减去1,但是1是不受影响的,原因非常简单:下标1在下标2之前,所以下标1不受下标2的影响

最后顺便批判一番!AC程序过不了样例系列!!!!!!

 1 #include<iostream>
 2 #include<iomanip>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<ctime>
 7 #include<cstdlib>
 8 #include<cmath>
 9 using namespace std;
10 const int maxn = 105;
11 const int maxt = 20086;
12 const int quz = 10005;
13 int n, t;
14 int f[maxn][maxt];
15 int a[maxn];
16 int ans[maxn];
17 
18 inline int read() {
19     int x = 0, y = 1;
20     char ch = getchar();
21     while(!isdigit(ch)) {
22         if(ch == '-') y = -1;
23         ch = getchar();
24     }
25     while(isdigit(ch)) {
26         x = (x << 1) + (x << 3) + ch - '0';
27         ch = getchar();
28     }
29     return x * y;
30 }
31 
32 int main() {
33     memset(f, 0, sizeof(f));
34     n = read(), t = read();
35     for(int i = 1; i <= n; ++i)
36         a[i] = read();
37      f[1][a[1] + quz] = 1;
38      f[2][a[1] - a[2] + quz] = -1;
39      for(int i = 3; i <= n; ++i)
40          for(int j = -10000 + quz; j <= 10000 + quz; ++j) {
41              if(f[i - 1][j] != 0) {
42                  f[i][a[i] + j] = 1;
43                  f[i][j - a[i]] = -1;
44              }
45          }
46     int s = quz + t;
47     for(int i = n; i >= 2; --i) {
48         ans[i] = f[i][s];
49         if(ans[i] == 1)
50             s -= a[i];
51         else if(ans[i] == -1) 
52             s += a[i];
53     }
54     int cnt = 0;
55     for(int i = 2; i <= n; ++i)
56         if(ans[i] == 1) {
57             cout << i - cnt - 1 << '\n';
58             cnt++;
59         }
60     for(int i = 2; i <= n; ++i) 
61         if(ans[i] == -1)
62             cout << 1 << '\n';
63 /*    for(; cnt + 1 <= n - 1; cnt++) 
64         cout << 1 << '\n';*/
65     return 0;
66 }

 

猜你喜欢

转载自www.cnblogs.com/ywjblog/p/9252394.html
今日推荐