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;
}

浙公网安备 33010602011771号