20210925 noip61

res

期望:rk5 30+20+20+70
实际:rk22 30+20+20+0
T4 \(a_i\) 可能 \(<0\),因此 DP 数组的初值要设为 \(-\inf\)
T4 sub4 数据锅了

rk1 szs 100+100+0+100
rk5 ycx 100+40+0+0
rk9 zjj 30+100+0+0
rk14 ys 30+20+0+50
rk14 zkx 0+100+0+0

交通

是个套路

把原图中每个点 \(i\) 出边所连的点 \(u_i,v_i\) 在新图中连边
原图中每个点的出入度都是 \(2\),因此新图中每个点的度数为 \(2\),一定会形成若干个偶环

留下原图中的边 \((i,u_i)\) 就等价于新图中边 \((u_i,v_i)\) 指向 \(u_i\)
由于要求最后每个点入度为 \(1\),因此新图中一个点有且仅有一个连边指向它,即每个偶环只有 \(2\) 种方案,答案即为 \(2^{cnt}\)\(cnt\) 为偶环数,并查集维护即可。

code
const int N = 1e5+5, mod = 998244353;
int n,a[N],b[N];

int cnt,fa[N];

LL Pow(LL x,LL y)
	{ LL res=1; for(;y;y>>=1,x=x*x%mod)if(y&1)res=res*x%mod; return res; }

int find(int x) { return fa[x]==x ? x : fa[x]=find(fa[x]); }

signed main() {
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
	read(n);
	For(i,1,2*n) { int x,y; read(x,y); (!a[x] ? a[x] : b[x]) = y; }
	For(i,1,n) fa[i] = i;
	For(i,1,n) fa[find(a[i])] = find(b[i]);
	For(i,1,n) cnt += find(i) == i;
	write(Pow(2,cnt));
	return iocl();
}

小P的单调数列

结论:答案序列最多划分成 \(2\) 个极长单调区间
证明:从平均的角度考虑,划分成 \(3\) 个的序列一定不比它扔掉 \(1\)\(2\) 个后的子序列优。

这样只要正着倒着各跑一次带权 LIS 即可,时间复杂度 \(O(n\log n)\)

code
const int N = 1e5+5;
int n,a[N];

int mx,lsh[N];
LL f[N],g[N];
double ans;

struct BIT {
	LL t[N];
	void clear() { memset(t,0,sizeof t); }
	void add(int i,LL x) { for(;i<=mx;i+=i&-i) ckmax(t[i],x); }
	LL query(int i) { LL res=0; for(;i;i-=i&-i) ckmax(res,t[i]); return res; }
} bit;

signed main() {
	freopen("b.in","r",stdin);
	freopen("b.out","w",stdout);
	read(n);
	For(i,1,n) read(a[i]), lsh[i] = a[i];
	sort(lsh+1,lsh+n+1), mx = unique(lsh+1,lsh+n+1)-lsh-1;
	For(i,1,n) {
		a[i] = lower_bound(lsh+1,lsh+mx+1,a[i])-lsh;
		f[i] = bit.query(a[i]-1)+lsh[a[i]], bit.add(a[i],f[i]);
		ckmax(f[i],f[i-1]), ckmax(ans,(double)f[i]);
	}
	bit.clear();
	rFor(i,n,1) {
		g[i] = bit.query(a[i])+lsh[a[i]], bit.add(a[i],g[i]);
		ckmax(g[i],g[i+1]), ckmax(ans,(f[i-1]+g[i])/2.0);
	}
	printf("%.3lf",ans);
	return 0;
}

矩阵

对于一个 \(3\times3\) 的矩阵,在操作过程中 \(a_{1,1}-a_{1,2}-a_{2,1}+a_{2,3}+a_{3,2}-a_{3,3}\) 的值一定,因此将前两行、前两列消成 \(0\) 后若 \(a_{3,3}\ne0\) 则一定无解。

这样只要将给定的矩阵前两行、前两列消成 \(0\) 即可,实际只需不到 \(2(n+m)\) 次操作

code
#define MT make_tuple

const int N = 1e3+5;
int n,m;
LL a[N][N];

vector<tuple<int,int,LL>> ans;

void add1(int i,LL x) { if( x ) {
	ans.pb(MT(1,i,x));
	For(j,1,m) a[i][j] += x;
}}
void add2(int j,LL x) { if( x ) {
	ans.pb(MT(2,j,x));
	For(i,1,n) a[i][j] += x;
}}
void add3(int k,LL x) { if( x ) {
	ans.pb(MT(3,k,x));
	for(int i = 1; i <= n && i+k <= m; ++i) if( i+k > 0 ) a[i][i+k] += x;
}}

signed main() {
	freopen("c.in","r",stdin);
	freopen("c.out","w",stdout);
	read(n,m); For(i,1,n) For(j,1,m) read(a[i][j]);
	For(j,1,m) add3(j-1,a[2][j]-a[1][j]), add2(j,-a[1][j]);
	For(i,3,n) add1(i,-a[i][2]), add3(1-i,-a[i][1]);
	For(i,3,n) For(j,3,m) if( a[i][j] ) puts("-1"), exit(0);
	write(ans.size());
	for(auto i : ans) write(get<0>(i),' '), write(get<1>(i),' '), write(get<2>(i));
	return iocl();
}

花瓶

\(O(n^3)\) 暴力 DP 显然:设 \(s\)\(a\) 前缀和,\(f[i,j]\) 为前 \(i\) 个花瓶,最后一段为 \([j+1,i]\) 的最大值,转移:

\[f[i,j]=\max_{k=0}^{j-1}\{f[j,k]+(s[i]-s[j])(s[j]-s[k]\} \]

明显的斜率优化,可以拆成

\[f[j,k]=(s[i]-s[j])s[k]+f[i,j]-s[i]s[j]+s[j]^2 \]

枚举 \(j\),用 \(k<j\) 构建凸包,用 \(i\) 在上面查询
问题是 \(s\) 不单调,而 \(O(n^2\log n)\) 并不能通过。
那就以 \(s[k]\) 递增的顺序构建凸包,以 \(s[i]\) 递减的顺序查询,这样就可以贪心地从凸包前面删点,单调队列维护即可。

时间复杂度 \(O(n^2)\)

code
const int N = 5e3+5;
int n,a[N];

LL s[N],f[N][N];
VI id;
int l,r,q[N];

LD K(int i,int j,int k) {
	if( s[i] == s[j] ) return f[k][i]>f[k][j] ? -1e15 : 1e15;
	return LD(f[k][i]-f[k][j]) / (s[i]-s[j]);
}

signed main() {
	freopen("d.in","r",stdin);
	freopen("d.out","w",stdout);
	read(n); For(i,1,n) read(a[i]), s[i] = s[i-1] + a[i];
	memset(f,0xcf,sizeof f);
	For(i,0,n) f[i][0] = 0, id.pb(i);
	sort(id.begin(),id.end(),[](const int &x,const int &y){return s[x]<s[y];});
	For(j,1,n) {
		l = 1, r = 0;
		for(int k : id) if( k < j ) {
			while( l<r && K(q[r],k,j) > K(q[r-1],q[r],j) ) --r;
			q[++r] = k;
		}
		for(auto it = id.rbegin(); it != id.rend(); ++it) {
			int i = *it;
			if( i > j ) {
				while( l<r && s[i]-s[j] < K(q[l],q[l+1],j) ) ++l;
				ckmax(f[i][j],(s[j]-s[i])*s[q[l]]+f[j][q[l]]+s[i]*s[j]-s[j]*s[j]);
			}
		}
	}
	write(*max_element(f[n],f[n]+n+1));
	return iocl();
}
posted @ 2021-09-25 20:10  401rk8  阅读(51)  评论(0编辑  收藏  举报