CodeForces 1242E Planar Perimeter
CodeForces 1242E Planar Perimeter
https://codeforces.com/contest/1242/problem/E
求这样的一个平面图,满足
- 存在 \(f\) 个面,第 \(i\) 个面为 \(a_i\) 边形
- 直径最小
- 无重边,自环
输出方案,一个数 \(n\) 表示点数,然后对于对于每个面输出 \(u_1,u_2,\cdots,u_{a_i}\) 表示图中存在这样的一个环.
\(1 \le f \le 10^5, 3 \le a_i \le 3 \times 10^5, \sum a_i \le 3 \times 10^5\)
Tutorial
可以通过操作将一个直径为 \(n\) 的平面图和一个 \(a_i\) 边形glue,且可以选择glue \(r\) 条边,这样之后得到一个直径为 \(n+a_i-2r\) 的平面图.
void glue(int x,int r,int m)
{
for(int i=1;i<r;++i)
{
an[x].push_back(q[--tl]);
}
an[x].push_back(q[tl-1]);
for(int i=r+1;i<m;++i)
{
an[x].push_back(q[tl++]=++n);
}
an[x].push_back(q[tl++]=q[hd++]);
}
// an[x]表示第x个多边形的环
// q[hd...tl]表示平面图当前的直径
// 第12行的目的为保证无重边
现在考虑如何选择 \(r\) .
首先将所有面按照 \(a_i\) 降序排列,然后将 \(i=2,3,\cdots,f\) 依次和 \(a_1\) 合并,且要让 \(r\) 在保证最后直径至少为 \(3\) 的情况下尽量大.为方便设 \(a_{n+1}=3\) ,则每次的 \(r=\min\{a_i-1,\lfloor \dfrac {(tl-hd+a_i-a_{i+1})}2 \rfloor\}\) ,第一项的目的是最大化 \(r\) ,第二项的目的是保证最后的直径至少为 \(3\)
Code
https://codeforces.com/contest/1242/submission/65031118
#include <algorithm>
#include <cstdio>
#include <iostream>
#include <vector>
#define debug(...) fprintf(stderr,__VA_ARGS__)
using namespace std;
inline char nc()
{
// return getchar();
static char buf[100000],*l=buf,*r=buf;
return l==r&&(r=(l=buf)+fread(buf,1,100000,stdin),l==r)?EOF:*l++;
}
template<class T> void read(T &x)
{
x=0; int f=1,ch=nc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=nc();}
while(ch>='0'&&ch<='9'){x=x*10-'0'+ch;ch=nc();}
x*=f;
}
const int maxf=1e5+50;
const int maxn=3e5+50;
const int maxnode=maxn+maxf;
int f;
int n;
int hd;
int tl;
int q[maxnode];
vector<int> an[maxf];
struct node
{
int x,id;
inline bool operator <(const node &other) const
{
return x>other.x;
}
} a[maxf];
void glue(int x,int r,int m)
{
for(int i=1;i<r;++i)
{
an[x].push_back(q[--tl]);
}
an[x].push_back(q[tl-1]);
for(int i=r+1;i<m;++i)
{
an[x].push_back(q[tl++]=++n);
}
an[x].push_back(q[tl++]=q[hd++]);
}
int main()
{
read(f);
for(int i=1;i<=f;++i)
{
read(a[i].x),a[i].id=i;
}
sort(a+1,a+f+1);
for(int i=1;i<=a[1].x;++i)
{
q[tl++]=++n;
an[a[1].id].push_back(n);
}
a[f+1].x=3;
for(int i=2;i<=f;++i)
{
int m=a[i].x;
int r=min(m-1,(tl-hd+m-a[i+1].x)/2);
glue(a[i].id,r,m);
}
printf("%d\n",n);
for(int i=1;i<=f;++i)
{
for(int j=0;j<an[i].size();++j)
{
if(j) printf(" ");
printf("%d",an[i][j]);
}
printf("\n");
}
return 0;
}