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 这个位置上的数,会造成什么影响,

  1. 对于pos之前的数都加上 val[pos] , 代表着,如果选择了pos 之前的数,那么pos 的排名就会+1,pos的贡献也会改变,这就相当于将pos的贡献加到了它的前面。
  2. 对于它后面会它的排名加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;
}

posted @ 2020-06-05 17:28  沙野博士  阅读(262)  评论(0)    收藏  举报