把过去和现在的笔记记录也搬了过来,也算是给以后留个念想吧,想想一开始打acm就是图一乐,后来发现这游戏还挺上头的,也算是度过了一段电竞生涯(xs) 早些时候的笔记写的好中二,连我自己看着都羞耻。 不过,就喜欢这种羞耻的感觉。 收录的题目大部分是个人认为质量不错的题目,以DP为主,非DP的题目都用※进行了标识。 当然,有些题解思路本身也是源自其他人的,不过除非特殊标注,否则都是用的自己的代码。
题目大意: CF 1637D Yet Another Minimization Problem 说实话感觉这题我的做法并不是正解,但是简单无脑。 题目大意为给定两个长度为n的数组,(n范围为100,数字范围也为100),你可以将他们俩对应位置的数进行交换,交换次数任意,求两个数组分别的数组内两两相加的和的平方和的和的最小值(有点绕),小列个式子可以发现问题可以转化为将a数组-b数组得到c数组,在c数组的每个数前面标加减号来使得结果的绝对值最小。
解:
由于数字范围为100,n也为100,实际上c数组的和最大为10000,最小为-10000,如果用线性dp的话数组为100*20000也就是1e6,完全符合要求,dp[i][j]表示进行到第i个数且和为j的情况,对于一个新的i,状态转移为dp[0][0]=1,dp[i][j+ci]=dp[i-1][j]和dp[i][j-ci]=dp[i-1][j],最后只要判断dp[i][n]=1中n绝对值最小的那个即可。 同时对于每一个值记录它对应的是加还是减,求结果的时候还需要用到。 为了偷懒不用map,写法看起来有点缺乏观赏性…… 像这种n等于100且每个n都有两种或多种选择的时候,状压是不可取的,毕竟是2^100嘛,可以注意到最后我们把这个接近2^100的可能性限定在了20000内,这真的是因为数组中数字大小绝对值在100以内吗?真的不是因为一共只有100个数吗,如果a[i]<=1e9的时候难道就不行了吗? 如果是去离散化,将每步得到的答案用set这种东西储存起来,然后dp…… 如果a1=1,a2=2,a3=4,…,a100=2^101还是寄,目前想不到解法。
好,Yet Another Minimization Problem 2 给定n(1<=n<=100),一个数组cn ,现在可以进行任意次操作,选定i使得c[i]=-c[i],现在要使任意次操作后得到的c数组之和绝对值最小,求该绝对值大小。
……挺无语的就 代码(当然不是问题2):
代码 代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <algorithm> #include <utility> #include <vector> #include <istream> #include <map> #include <cstring> #include <string> #define ll long long #define maxn 200005 #define mdl 998244353 using namespace std;int a[101 ],b[101 ],c[101 ];int dp[20001 ][101 ], track[20001 ][101 ];int v[20001 ][101 ];int main () { std::ios::sync_with_stdio (false ); cin.tie (0 ); cout.tie (0 ); int t; cin >> t; while (t--) { memset (v, 0 , sizeof (v)); int n; cin >> n; ll ans = 0 ; for (int i = 0 ; i < n; i++) { cin >> a[i]; } for (int i = 0 ; i < n; i++) { cin >> b[i]; c[i] = a[i] - b[i]; } int fina = 0 , mi = 1e9 ; for (int i = 0 ; i < n; i++) { if (i == 0 ) { dp[10000 + c[i]][0 ] = c[i]; track[10000 +c[i]][0 ] = 1 ; dp[10000 - c[i]][0 ] = -c[i]; track[10000 - c[i]][0 ] = 0 ; v[10000 + c[i]][0 ] = 1 ; v[10000 - c[i]][0 ] = 1 ; } else { for (int j = 0 ; j <= 20000 ; j++) { if (v[j][i - 1 ] == 0 )continue ; dp[j + c[i]][i] = j-10000 + c[i]; track[j + c[i]][i] = 1 ; dp[j - c[i]][i] = j-10000 - c[i]; track[j - c[i]][i] = 0 ; v[j + c[i]][i] = 1 ; v[j - c[i]][i] = 1 ; if (i == n - 1 ) { int d1 = dp[j + c[i]][i]; if (d1 < 0 )d1 = -d1; int d2 = dp[j - c[i]][i]; if (d2 < 0 )d2 = -d2; if (d1 < mi) { fina = j + c[i]; mi = d1; } if (d2 < mi) { fina = j - c[i]; mi = d2; } } } } } for (int i = n - 1 ; i >=0 ; i--) { if (track[fina][i] == 0 ) { int tmp = a[i]; a[i] = b[i]; b[i] = tmp; fina += c[i]; } else fina -= c[i]; } for (int i = 0 ; i < n; i++) { ans += a[i] * a[i] * (n - 1 ); ans += b[i] * b[i] * (n - 1 ); for (int j = 0 ; j < i; j++) { ans += 2 *a[i] * a[j]; ans += 2 *b[i] * b[j]; } } cout << ans << endl; } }
Copyright Notice: 此文章版权归EmiteInna所有,多看看吧。