AtCoder Regular Contest 103
Contest Link Official Editorial
C - ////
定义一个序列为 /\/\/\/ ,当且仅当满足:
- \(\forall i=1\sim n-2,a_i=a_{i+2}\)
- 序列中有恰好两个不同的数
保证给出的序列长度为偶数。求将给出的长度为 \(n\) 的序列变成 /\/\/\/ 序列的最小替换次数。\(2\leq n\leq 1e5,1\leq v_i\leq 1e5\) .
Solution
简单题。直接桶排一下,然后扫一遍得到奇数位置和偶数位置最大、第二大的众数,如果最大的两个不同,那么直接输出 \(n\) 减去这两个;否则,在奇数最大+偶数第二大和奇数第二大+偶数最大里取一个最大值即可。
//Author:RingweEH
const int N=1e5+10;
int n,cnt_even[N],cnt_odd[N];
int a[N],b[N];
int main()
{
n=read();
for ( int i=1; i<=n; i++ )
if ( i&1 ) cnt_odd[read()]++;
else cnt_even[read()]++;
int emx_1=0,emx_2=0;
for ( int i=1; i<=100000; i++ )
if ( cnt_even[i]>cnt_even[emx_1] ) emx_2=emx_1,emx_1=i;
else if ( cnt_even[emx_2]<cnt_even[i] ) emx_2=i;
int omx_1=0,omx_2=0;
for ( int i=1; i<=100000; i++ )
if ( cnt_odd[i]>cnt_odd[omx_1] ) omx_2=omx_1,omx_1=i;
else if ( cnt_odd[omx_2]<cnt_odd[i] ) omx_2=i;
if ( omx_1^emx_1 ) { printf( "%d\n",n-cnt_odd[omx_1]-cnt_even[emx_1] ); return 0; }
omx_2=cnt_odd[omx_2]; omx_1=cnt_odd[omx_1];
emx_1=cnt_even[emx_1]; emx_2=cnt_even[emx_2];
int now=max( omx_2+emx_1,omx_1+emx_2 );
printf( "%d\n",n-now );
return 0;
}
D - Robot Arms
给定 \(n\) 个点,要求构造出一个序列 \(d\) ,并对每个点构造方案:
- 使用
LRUD给出一个长度为 \(m-1\) 的操作序列,使得第 \(i\) 个操作执行 \(d[i]\) 次后,能到达这个点 L=LeftR=RightU=UpD=Down
Solution
显然,如果 \(x_i+y_i\) 的奇偶性不同,肯定无解。而偶数的情况显然能通过奇数得到,所以考虑如何凑出所有的奇数。
用二进制来构造,通过 \(1,2,\cdots ,2^k\) 能得到所有 \(|x|+|y|<2^{k+1}\) 且 \(x+y\) 为奇数的位置。
当 \(k=0\) 时,显然满足;
设 \(1\sim 2^{k-1}\) 满足,不妨令 \(|x|>|y|\) ,那么 \(x,y\) 至多只有一个数的第 \(k\) 位为 \(1\) ,如果 \(|x|>2^k\) ,那么令 \(|x|-=2^k\) ,否则 \(|x|=2^k-|x|\) ,仍然满足。

递归求解即可。我因为文件头TLE了两发,因为写错了LRUD WA了若干发,判无解变量没有and又WA了两发
//Author:RingweEH
const int N=1010,M=35;
struct Node
{
ll x,y;
}a[N];
int n;
ll powe[M];
bool Pd( ll x,ll y,int k )
{
return abs(x)+abs(y)<powe[k+1];
}
void Work( ll x,ll y,int lim )
{
if ( lim>=0 )
{
if ( abs(x)>abs(y) )
{
if ( Pd(x-powe[lim],y,lim-1) ) { Work(x-powe[lim],y,lim-1); printf( "R" ); }
else { Work(x+powe[lim],y,lim-1); printf( "L" ); }
}
else
{
if ( Pd(x,y-powe[lim],lim-1) ) { Work(x,y-powe[lim],lim-1); printf( "U" ); }
else { Work(x,y+powe[lim],lim-1); printf( "D" ); }
}
}
}
int main()
{
powe[0]=1;
for ( int i=1; i<M; i++ )
powe[i]=powe[i-1]<<1;
n=read(); bool fl=1;
for ( int i=1; i<=n; i++ )
{
a[i].x=read(),a[i].y=read();
if ( i>1 ) fl&=(((a[i].x+a[i].y)&1)==((a[i-1].x+a[i-1].y)&1));
}
if ( !fl ) { printf( "-1" ); return 0; }
if ( (a[1].x+a[1].y)&1 )
{
printf( "%d\n",M );
for ( int i=0; i<M; i++ )
printf( "%lld ",powe[i] );
printf( "\n" );
}
else
{
printf( "%d\n",M+1 );
printf( "1 " );
for ( int i=0; i<M; i++ )
printf( "%lld ",powe[i] );
printf( "\n" );
}
for ( int i=1; i<=n; i++ )
{
if ( (a[i].x+a[i].y)%2==0 )
{
printf( "L" ),a[i].x++;
}
Work( a[i].x,a[i].y,M-1 );
printf( "\n" );
}
return 0;
}
E - Tr/ee
给定一个长度为 \(n\) 的序列 \(s\) ,构造一棵树满足如下条件:
- 点从 \(1\sim n\) 标号,边从 \(1\sim n-1\) 标号;
- 如果 \(s[i]=1\) ,那么能通过删除一条边得到一个大小为 \(i\) 的连通块;
- 如果 \(s[i]=0\) ,那么不能通过删除一条边得到一个大小为 \(i\) 的连通块。
\(2\leq n\leq 1e5\) ,无解输出 \(-1\) .
Solution
首先考虑无解:
- \(s[1]=0\) 或者 \(s[n]=1\) ,显然不行
- \(s[i]=1\) 且 \(s[n-i]=0\) ,如果能分出一个那么一定也能分出另一个。
然后就可以愉快构造了,还是比较简单的。
设当前加到了第 \(i\) 条边,那么当前连通块里有 \(i+1\) 个点。如果 \(s[i]=1\) ,那么也就是说加这条边之前的那个大小为 \(i\) 的连通块要能独立出来,那么下一次加边就从新的这个端点加,否则还是在老的端点加。设一个 \(rt\) 来表示即可。
//Author:RingweEH
const int N=1e6+10;
char s[N];
int main()
{
scanf( "%s",s+1 ); int n=strlen(s+1);
if ( s[1]=='0' || s[n]=='1' ) { printf( "-1" ); return 0; }
for ( int i=1; i<=n; i++ )
if ( s[i]=='1' && s[n-i]=='0' ) { printf( "-1" ); return 0; }
int rt=1;
for ( int i=2; i<=n; i++ )
{
printf( "%d %d\n",rt,i );
if ( s[i-1]=='1' ) rt=i;
}
return 0;
}
F - Distance Sums
给定一个长度为 \(n\) 的序列 \(D\) ,构造满足以下条件的一棵树:
- 点标号为 \(1\sim n\) ,边标号为 \(1\sim n-1\)
- 对于每个点 \(i\) ,它到所有点的距离之和为 \(D_i\) (边长为 \(1\) )
\(2\leq n\leq 1e5,1\leq D_i\leq 1e12\) .
Solution
显然,\(D_i\) 最大的一个点一定是叶子节点,最小的一定是重心。那么可以从叶子节点开始倒推上去。
对于一个点 \(u\) ,设一个子节点为 \(v\) ,那么显然,\(D_u=D_v+2\cdot siz[v]-n\) 。也就是说,我们可以通过一个 \(D\) 较大的 \(v\) 反推出其父亲 \(u\) ,这样就能从一个叶子节点开始,从大到小遍历 \(D_i\) ,然后一个一个找父亲,更新 \(siz\) 即可。
注意到这样只满足了差值关系,所以最后还要 DFS 验证一遍。
//Author:RingweEH
#define PII pair<int,int>
#define mp make_pair
#define pb push_back
const int N=1e5+10;
int n,siz[N],dep[N];
pair<ll,int> a[N];
vector<int> g[N];
vector<PII> ans;
void Dfs( int u,int fa )
{
dep[u]=dep[fa]+1;
for ( int v : g[u] )
if ( v^fa ) Dfs( v,u );
}
int main()
{
n=read();
for ( int i=1; i<=n; i++ )
a[i]=mp(read(),i);
sort( a+1,a+1+n );
for ( int i=1; i<=n; i++ )
siz[i]=1;
for ( int i=n; i>1; i-- )
{
ll del=2*siz[a[i].second]-n+a[i].first;
int pos=lower_bound( a+1,a+1+n,mp(del,0) )-a;
if ( a[pos].first^del ) { printf( "-1" ); return 0; }
int u=a[i].second,v=a[pos].second;
ans.pb( mp(u,v) );
g[u].pb(v); g[v].pb(u); siz[v]+=siz[u];
}
dep[0]=-1;
Dfs( a[1].second,0 ); ll sum=0;
for ( int i=1; i<=n; i++ )
sum+=dep[i];
if ( sum!=a[1].first ) { printf( "-1" ); return 0; }
for ( PII i : ans )
printf( "%d %d\n",i.first,i.second );
return 0;
}

浙公网安备 33010602011771号