day7-徐翊轩
T1 CF573E Bear and Bowling
- 给定一个长度为 n 的序列 \(a_{1\dots n}\)。
- 你要求一个\(a\) 的子序列 \(b_{1\dots m}(可以为空)\),使得 \(\sum_{i=1}^m ib_i\) 的值最大。
- \(n \le 10^5,|a_i| \le 10^7\)。
啊,这题我就会个,n^2的dp,,,
考虑,一开始有一个空的序列,然后往它里面加元素。
比如加进去了 pos 这个位置上的数,会造成什么影响,
- 对于pos之前的数都加上 val[pos] , 代表着,如果选择了pos 之前的数,那么pos 的排名就会+1,pos的贡献也会改变,这就相当于将pos的贡献加到了它的前面。
- 对于它后面会它的排名加1,
于是乎,对于每个数,维护一个k表示排名,还有一个b表示要加的所有数的和,
每次,选择贡献最大的加到选择的序列中,然后对累积的答案取max,这样的贪心是正确的。
对于这两个操作,可以分块解决。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<string>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#include<set>
#include<map>
using namespace std;
typedef long long LL;
#define int long long
const int N = 1e5+10 , Sqrt = 300 , M = N / Sqrt + 10;
const LL inf = 0x3f3f3f3f3f3f3f3f;
inline int read()
{
register int x = 0 , f = 0; register char c = getchar();
while(c < '0' || c > '9') f |= c == '-' , c = getchar();
while(c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0' , c = getchar();
return f ? -x : x;
}
int n;
int a[N] , L[M] , R[M] , pos[N] , B[N] , db[N] , dk[N] , ql[M] , qr[M] , p[N] , vis[N] , q[N];
double calc(int i , int j)
{
if(a[i] == a[j])
{
if(B[i] == B[j]) return 1;
if(B[i] < B[j]) return 1e99; else return -1e99;
}
return (B[j] - B[i]) / (double)(a[j] - a[i]);
}
void build(int id)
{
for(int i = L[id] ; i <= R[id] ; ++i)
B[p[i]] += db[id] + dk[id] * a[p[i]];
db[id] = dk[id] = 0;
int &l = ql[id] , &r = qr[id]; l = L[id]; r = L[id] - 1;
for(int i = L[id] ; i <= R[id] ; ++i) if(!vis[p[i]])
{
int x = p[i];
while(l < r && calc(q[r - 1] , q[r]) < calc(q[r] , x)) r--;
q[++r] = x;
}
}
inline pair<LL,int> Ask(int id)
{
int &l = ql[id] , r = qr[id];
while(l < r && calc(q[l] , q[l + 1]) >= -dk[id]) l++;
if(l > r) return make_pair(-inf , 0);
return make_pair(B[q[l]] + db[id] + dk[id] * a[q[l]] , q[l]);
}
signed main()
{
n = read();
for(int i = 1 ; i <= n ; ++i) B[i] = a[i] = read() , p[i] = i;
for(int i = 1 ; i <= n ; ++i) pos[i] = (i - 1) / Sqrt + 1;
for(int i = 1 ; i <= pos[n] ; ++i) L[i] = (i - 1) * Sqrt + 1 , R[i] = i * Sqrt;
R[pos[n]] = n;
for(int i = 1 ; i <= pos[n] ; ++i)
sort(p + L[i] , p + R[i] + 1 , [](int A , int B){ return a[A] < a[B]; }) , build(i);
LL nowval = 0 , ans = 0;
for(int i = 1 ; i <= n ; ++i)
{
pair<LL,int> now = make_pair(-inf , 0);
for(int j = 1 ; j <= pos[n] ; ++j) now = max(now , Ask(j));
nowval += now.first; ans = max(ans , nowval);
int ps = now.second , id = pos[ps];
for(int j = 1 ; j < id ; ++j) db[j] += a[ps];
for(int j = pos[n] ; j > id ; --j) dk[j]++;
for(int j = L[id] ; j < ps ; ++j) B[j] += a[ps];
for(int j = R[id] ; j > ps ; --j) B[j] += a[j];
vis[ps] = 1; build(id);
}
cout << ans << '\n';
return 0;
}
T3 AT4432 [ARC103B] Robot Arms
给定 n 组坐标。构造长度为 m的序列 \(\{c_n\}\)和 \(n\) 组包含 LRUD
的路径,满足对于每一组坐标:
- \(c_i\)表示第 \(i\) 步「步长」。
- 对于每个坐标,从$ (0,0)$ 开始走,共走 \(m\) 步。第 \(i\) 步可以让 \((x,y)\) 变成 \((x±c_i,y)\) 或 \((x,y±c_i)\) 。
- 走完 m 次之后,恰好走到这组坐标。
- 要求 \(m\leq 40,c_i\leq 10^{12}\) 。
\(1\leq n\leq 1000\)
然后,考虑倍增构建,
...........
...........
...........
...........
.....#.....
....#.#....
.....#.....
...........
...........
...........
...........
...........
...........
.....#.....
....#&#....
...#.#.#...
..#&#.#&#..
...#.#.#...
....#&#....
.....#.....
...........
...........
然后就没了。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<string>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#include<set>
#include<map>
using namespace std;
typedef long long LL;
const int N = 1010;
#define int long long
inline int read()
{
register int x = 0 , f = 0; register char c = getchar();
while(c < '0' || c > '9') f |= c == '-' , c = getchar();
while(c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0' , c = getchar();
return f ? -x : x;
}
int n;
int x[N] , y[N] , len[50];
inline int Abs(int x) { return x < 0 ? -x : x; }
signed main()
{
n = read();
for(int i = 1 ; i <= n ; ++i) x[i] = read() , y[i] = read();
int tmp = Abs(x[1] + y[1]) & 1;
for(int i = 2 ; i <= n ; ++i) if((Abs(x[i] + y[i]) & 1) != tmp) { puts("-1"); return 0; }
cout << (32 - tmp) << '\n'; // (0 , 0)是偶数;
int tot = 0; len[tot = 1] = 1; cout << 1 << ' ';
if(tmp)
for(int i = 1 ; i <= 30 ; ++i) len[++tot] = 1 << i , cout << len[tot] << ' ';
else
for(int i = 0 ; i <= 30 ; ++i) len[++tot] = 1 << i , cout << len[tot] << ' ';
cout << '\n';
char ans[32];
for(int i = 1 ; i <= n ; ++i)
{
int nowx = 0 , nowy = 0;
for(int j = tot ; j >= 1 ; --j)
{
int dx = Abs(nowx - x[i]) , dy = Abs(nowy - y[i]);
if(dx > dy)
{
if(nowx < x[i]) nowx += len[j] , ans[j] = 'R'; else nowx -= len[j] , ans[j] = 'L';
}
else
{
if(nowy < y[i]) nowy += len[j] , ans[j] = 'U'; else nowy -= len[j] , ans[j] = 'D';
}
}
for(int j = 1 ; j <= tot ; ++j) putchar(ans[j]); cout << '\n';
}
return 0;
}