[P5665][CSP2019D2T2] 划分

先说说部分分做法吧

1.\(n \leq 10\) 指数级瞎草都可以2333

2.\(n \leq 50\) 好像并没有什么做法…也许给剪枝的人部分分吧

3.\(n \leq 400\) 这个复杂度是给 \(O(n^3)\) 过的… 大概就是 考虑一个数组 \(dp_{n,n}\) 每次枚举转移点\(i , j ,k\)

\[dp_{j,k} = min\{ dp_{i,j} + (sum_k - sum_j)^2\} \]

4.\(n \leq 5000\)

这道题有个显而易见的结论:最后一段尽量小 答案会最优…

所以每次考虑转移能转移的 最小的直接二分就行了吧…这样就少掉一维空间 时间也变成 \(O(n^2 \log n)\)
不过仔细想想好像 \(n^2\)就行了

  1. 正解吧…… 这个题的大毒瘤出题人出的题要用高精度 顺手还卡了内存… 好像把zyy和hy等一堆神仙卡掉了…

由于是单调的 所以单调队列维护一个 \(\text{d(i)}\) 即以 \(i\) 结尾的这一段的值…

所以维护一个单调队列 然后注意一点 记录每个点的前驱\(pre_i\) 最后统计答案 这样才能保证int128空间不会爆炸
前排赠送 \(\texttt{88pts}\) 代码

\(\texttt{code}\)

#include<bits/stdc++.h>
#define int long long
using namespace std ;
const int N = 4e7 + 10 ;
int n , type , a[N] , q[N] , dp[N] , sum[N] , d[N] ;
signed main() {
  ios :: sync_with_stdio(false) ; cin.tie(nullptr) ; cout.tie(nullptr) ;
  cin >> n >> type ;
  for(register int i = 1 ; i <= n ; i ++) { cin >> a[i] ; sum[i] = sum[i - 1] + a[i] ; }
  int h , t ; q[h = t = 0] = 0 ;
  for(register int i = 1 ; i <= n ; i ++) {
    while(h < t && d[q[h + 1]] + sum[q[h + 1]] <= sum[i]) ++ h ;
    d[i] = sum[i] - sum[q[h]] ; dp[i] = dp[q[h]] + (d[i] * d[i]) ;
    while(h < t && d[q[t]] + sum[q[t]] >= d[i] + sum[i]) -- t ;
    q[++ t] = i ;
  }
  cout << dp[n] << '\n' ;
  return 0 ;
}

至于高精懒得写… 直接拿int128水了 然后把dp数组类型改成int128 和原来的分数莫得区别2333
直接转移竟然\(\texttt{1G}\) 内存都不够用 佛了…

\(\texttt{code}\)

#include<bits/stdc++.h>
using namespace std ;
const int N = 4e7 + 10 ;
const int M = 1e5 + 10 ;
const int mod = (1 << 30) ;
int n , type , x , y , z , m ;
int a[N] , b[N] , p[M] , l[M] , r[M] , q[N] , pre[N] ;
long long sum[N] ;
inline long long d(int x) { return sum[x] - sum[pre[x]] ; }
signed main() {
  ios :: sync_with_stdio(false) ; cin.tie(nullptr) ; cout.tie(nullptr) ;
  cin >> n >> type ;
  if(type) {
		cin >> x >> y >> z >> b[1] >> b[2] >> m ;
    for(register int i = 1 ; i <= m ; i ++) { cin >> p[i] >> l[i] >> r[i] ; }
    for(register int i = 3 ; i <= n ; i ++) { b[i] = (0ll + 1ll * b[i - 1] * x + 1ll * b[i - 2] * y + z) % mod ; }
    for(register int i = 1 ; i <= m ; i ++)
      for(register int j = p[i - 1] + 1 ; j <= p[i] ; j ++) { a[j] = (b[j] % (r[i] - l[i] + 1)) + l[i] ; sum[j] = sum[j - 1] + a[j] ; }
	}
  else {
  	for(register int i = 1 ; i <= n ; i ++) { cin >> a[i] ; sum[i] = sum[i - 1] + a[i] ; }
	} int h , t ; q[h = t = 0] = 0 ;
  for(register int i = 1 ; i <= n ; i ++) {
    while(h < t && d(q[h + 1]) + sum[q[h + 1]] <= sum[i]) ++ h ; 
		pre[i] = q[h] ;
    while(h < t && d(q[t]) + sum[q[t]] >= d(i) + sum[i]) -- t ;
    q[++ t] = i ;
  }  int now = n ; __int128 ans = 0 , tmp = 1 ;
	while(now) { tmp = d(now) ; tmp *= d(now) ; ans += tmp ; now = pre[now] ; }
	int st[50] , tp = 0 ;
	while(ans) { st[++ tp] = ans % 10 ; ans /= 10 ; }
	while(tp) { cout << st[tp --] ; }
  return 0 ;
}

别喷int128啊

posted @ 2019-11-19 16:52  _Isaunoya  阅读(265)  评论(0编辑  收藏  举报