CF934 题解

A

范围很小,可以直接 \(O(n^2 m)\) 枚举。

复杂度较低的做法是枚举 \(A\) 的决策,然后通过求出最大的正乘积以及最大负乘积来更新答案。用 multiset 来维护 \(A\) 操作后的序列也许实现上较为简单。

B

简单贪心,尽可能选 8,奇数情况额外选个 9 (或其他贡献为 \(1\) 的数码)。

C

发现答案由 [1s] [2s, 1s] [2s] 组成,考虑用 \(O(N^2)\) 的 DP 预处理出中间区间 [2s, 1s] 的贡献。

// Problem: C. A Twisty Movement
// Contest: Codeforces - Codeforces Round 462 (Div. 2)
// URL: https://codeforces.com/contest/934/problem/C
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
 
#define debug(x) cerr << #x << ": " << (x) << endl
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define dwn(i,a,b) for(int i=(a);i>=(b);i--)
#define SZ(a) ((int) (a).size())
#define pb push_back
#define all(x) (x).begin(), (x).end()
 
#define x first
#define y second
using pii = pair<int, int>;
using ll = long long;
 
inline void read(int &x){
    int s=0; x=1;
    char ch=getchar();
    while(ch<'0' || ch>'9') {if(ch=='-')x=-1;ch=getchar();}
    while(ch>='0' && ch<='9') s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
    x*=s;
}

const int N=2020;

int n, w[N];
int f[N][N][2];
int c[N][2];

void solve(){
	cin>>n;
	rep(i, 1, n) read(w[i]);
	rep(i, 1, n){
		rep(j, 0, 1) c[i][j]=c[i-1][j];
		c[i][w[i]&1]++;
	}
	
	rep(len, 1, n){
		rep(l, 1, n-len+1){
			int r=l+len-1;
			if(l==r){
				f[l][l][w[l]&1]=1;
			}
			else{
				rep(k, 0, 1) f[l][r][k]=f[l][r-1][k];
				if(w[r]&1){
					f[l][r][1]=max(f[l][r][1], f[l][r-1][0]+1);
					f[l][r][1]=max(f[l][r][1], f[l][r-1][1]+1);
				}
				else{
					f[l][r][0]=max(f[l][r][0], f[l][r-1][0]+1);
				}
			}
		}
	}
	
	int res=0;
	rep(l, 1, n) rep(r, l, n){
		int c0=c[r][0]-c[l-1][0];
		int c1=c[r][1]-c[l-1][1];
		int x=(c[l-1][1]+max(f[l][r][0], f[l][r][1])+c[n][0]-c[r][0]);
		int y=(c[l-1][1]+c0+c[n][0]-c[r][0]);
		int z=(c[l-1][1]+c1+c[n][0]-c[r][0]);
		res=max({res, x, y, z});
	}
	cout<<res<<"\n";
}

signed main(){
	solve();
	return 0;
}

但其实有更简单的线性 DP 做法:

由于答案的结构为 [1s] [2s] [1s] [2s],所以可以使用 \(f[i, 0/1/2/3]\) 刻画这个结构(状态)。

const int N=2020;

int w[N];
int f[N][4];

void solve(){
	int n; cin>>n;
	rep(i, 1, n) read(w[i]);
	rep(i, 1, n){
		rep(j, 0, 3) f[i][j]=f[i-1][j];
		if(w[i]==1){
			f[i][0]=max(f[i][0], f[i-1][0]+1);
			f[i][2]=max({f[i][2], f[i-1][1]+1, f[i-1][2]+1});
		}
		else{
			f[i][1]=max({f[i][1], f[i-1][0]+1, f[i-1][1]+1});
			f[i][3]=max({f[i][3], f[i-1][2]+1, f[i-1][3]+1});
		}
	}
	cout<<*max_element(f[n], f[n]+4)<<"\n";
}

D

分析

提供一个简洁易懂的做法:

注意到 \(f(-k) = p\),也就是说 \(f(-k) = \sum_{i=0}^{d-1} a_i (-k)^i = p\),那本质上就是在求以 \(-k\) 为基的 \(p\) 的表出。

故做法类似于十进制,只不过是把基底 \(b = 10\) 换成 \(b=-k\) 。考虑除式 \(p = q b + r\),可以发现 \(r\) 对应着 \(a_i \geq 0\),所以做除法的时候注意把 \(r\) 调整到 \([0, k-1]\) 即可。

代码

// Problem: D. A Determined Cleanup
// Contest: Codeforces - Codeforces Round 462 (Div. 2)
// URL: https://codeforces.com/contest/934/problem/D
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
 
#define debug(x) cerr << #x << ": " << (x) << endl
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define dwn(i,a,b) for(int i=(a);i>=(b);i--)
#define SZ(a) ((int) (a).size())
#define pb push_back
#define all(x) (x).begin(), (x).end()
 
#define x first
#define y second
#define int long long
using pii = pair<int, int>;
using ll = long long;
 
inline void read(int &x){
    int s=0; x=1;
    char ch=getchar();
    while(ch<'0' || ch>'9') {if(ch=='-')x=-1;ch=getchar();}
    while(ch>='0' && ch<='9') s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
    x*=s;
}

void solve(){
	int p, k; cin>>p>>k;
	const int b=-k;
	// p = qb + r (r>=0)
	vector<int> a;
	while(p){
		int r=p%b, q=(p-r)/b;
		if(r<0) r+=-b, ++q;
		p=q;
		a.pb(r);
	}
	cout<<a.size()<<"\n";
	for(auto e: a) cout<<e<<" ";
	puts("");
}

signed main(){
	solve();
	return 0;
}

补充

我 VP 的时候没有想到上面的做法,用了一种比较麻烦的做法,这里简单说一下供参考:

\(q(x) = \sum b_i x^i, ~ b_0 = p\)。那根据题目约束,我们有 \(a_i = b_i k + b_{i-1} \in [0, k-1]\)

故可以考虑解上面的不等式组得到 \(b_i\),然后将 \(a_i\) 还原出来。

代码:

void solve(){
	int p, k; cin>>p>>k;
	vector<int> b={p};
	while(b.back()<0 || b.back()>=k){
		int nb=(b.back()>=0? -(b.back()/k): -b.back()/k+(-b.back()%k!=0? 1: 0));
		b.pb(nb);
	}
	vector<int> a;
	rep(i, 1, SZ(b)-1) a.pb(b[i]*k+b[i-1]);
	a.pb(b.back());
	cout<<a.size()<<"\n";
	for(auto e: a) cout<<e<<" ";
	puts("");
}
 
signed main(){
	solve();
	return 0;
}

E

分析

本质上是求平面图的面数 \(F\)

根据欧拉公式,\(V - E + F = C + 1\),其中 \(V\) 是点数,\(E\) 是边数,\(F\) 是面数,\(C\) 是连通块数。

\(C\) 可以用并查集维护。

\(V\) 通过求出圆之间所有交点并去重得到。

对于 \(E\),考虑对于每个圆,有多少个交点落在这个圆上,把这些交点数求和即可(因为注意到一段弧不可能被多个圆共有,不需要去重)。

代码

// Problem: E. A Colourful Prospect
// Contest: Codeforces - Codeforces Round 462 (Div. 2)
// URL: https://codeforces.com/contest/934/problem/E
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
 
#define debug(x) cerr << #x << ": " << (x) << endl
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define dwn(i,a,b) for(int i=(a);i>=(b);i--)
#define SZ(a) ((int) (a).size())
#define pb push_back
#define all(x) (x).begin(), (x).end()
 
#define x first
#define y second
using pii = pair<int, int>;
using ll = long long;
 
inline void read(int &x){
    int s=0; x=1;
    char ch=getchar();
    while(ch<'0' || ch>'9') {if(ch=='-')x=-1;ch=getchar();}
    while(ch>='0' && ch<='9') s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
    x*=s;
}

// V - E + F = C + 1

using db = double;

const int N=10;
const db eps=1e-10;

int sign(db a){
	return a<-eps? -1: a>eps;
}

int cmp(db x, db y){
	return sign(x-y);
}

struct P{
	db x, y;
	
	P(){}
	
	P(db x, db y): x(x), y(y){}
	
	P operator + (P p){
		return {x+p.x, y+p.y};
	}
	
	P operator - (P p){
		return {x-p.x, y-p.y};
	}
	
	P operator * (db d){
		return {x*d, y*d};
	}
	
	P operator / (db d){
		return {x/d, y/d};
	}
	
	db abs(){
		return sqrt(abs2());
	}
	
	db abs2(){
		return x*x+y*y;
	}
	
	P rot90(){
		return P(-y, x);
	}
	
	P unit(){
		return *this/abs();
	}
	
	db dis(P p){
		return (*this-p).abs();
	}
	
	bool operator < (const P &o){
		return cmp(x, o.x)? x<o.x: y<o.y;
	}
};

struct C{
	P o;
	db r;
	
	void read(){
		cin>>o.x>>o.y>>r;
	}
};

vector<P> isCC(C c1, C c2){
	db d=c1.o.dis(c2.o);
	db r1=c1.r, r2=c2.r;
	if(cmp(d, r1+r2)==1) return {};
	if(cmp(d, abs(r1-r2))==-1) return {};
	d=min(d, r1+r2);
	db y=(r1*r1 + d*d - r2*r2) / (d*2);
	db x=sqrt(r1*r1-y*y);
	P dr=(c2.o-c1.o).unit();
	P q1=c1.o+dr*y, q2=dr.rot90()*x;
	return {q1-q2, q1+q2};
}

bool PonC(P p, C c){
	return cmp(c.r, p.dis(c.o))? 0: 1;
}

struct DSU{
	int n;
	int f[N];
	
	// 记得 init
	void init(int _n){
		n=_n;
		rep(i, 1, n){
			f[i]=i;
		}
	}
	
	int find(int x){
		return x==f[x]? x: f[x]=find(f[x]);
	}
	
	void merge(int u, int v){
		u=find(u), v=find(v);
		if(u==v) return;
		f[u]=v;
	}
	
	int total(){
		int cnt=0;
		rep(i, 1, n) cnt+=(i==find(i));
		return cnt;
	}
}dsu;

int n;
C c[N];

void solve(){
	cin>>n;
	rep(i, 1, n) c[i].read();
	vector<P> b;
	dsu.init(n);
	rep(i, 1, n) rep(j, i+1, n){
		auto tmp=isCC(c[i], c[j]);
		for(auto e: tmp) b.pb(e);
		if(tmp.size()){
			dsu.merge(i, j);
		}
	}
	
	{
		// unique b
		sort(all(b));
		vector<P> nb;
		rep(i, 0, SZ(b)-1){
			bool dup=false;
			if(i && !cmp(b[i].x, b[i-1].x) && !cmp(b[i].y, b[i-1].y)){
				dup=true;
			}
			if(!dup) nb.pb(b[i]);
		}
		b=nb;
	}
	
	int C=dsu.total();
	int V=SZ(b);
	int E=0;
	rep(i, 1, n){
		for(auto e: b){
			if(PonC(e, c[i])) ++E;
		}
	}
	cout<<C+1+E-V<<"\n";
}

signed main(){
	solve();
	return 0;
}
posted @ 2025-08-03 01:42  HinanawiTenshi  阅读(13)  评论(0)    收藏  举报