[AtCoder Regular Contest 123] 题解


ARC123

A - Arithmetic Sequence

大讨论

只能 + 1 +1 +1,先固定中间的数,看两边加谁,如果都是加负数说明是中间的数需要加

#include <cstdio>
#include <iostream>
using namespace std;
#define int long long
int x, y, z;

int Fabs( int x ) {
	return x < 0 ? -x : x;
}

signed main() {
	scanf( "%lld %lld %lld", &x, &y, &z );
	if( x > z ) swap( x, z );
	int d1 = y - x, d2 = z - y;
	int x1 = y - d2, z1 = y + d1;
	if( x1 >= x ) printf( "%lld\n", x1 - x );
	else if( z1 >= z ) printf( "%lld\n", z1 - z );
	else if( ( z - x ) & 1 ) printf( "%lld\n", x + ( z - x ) / 2 - y + 2 );
	else printf( "%lld\n", x + ( z - x ) / 2 - y );
	return 0;
}

B - Increasing Triples

排序一边,贪心的有尽可能让小小小,大大大配对出现,双指针扫即可

#include <cstdio>
#include <algorithm>
using namespace std;
#define maxn 100005
int A[maxn], B[maxn], C[maxn];
int n;

int main() {
	scanf( "%d", &n );
	for( int i = 1;i <= n;i ++ )
		scanf( "%d", &A[i] );
	for( int i = 1;i <= n;i ++ )
		scanf( "%d", &B[i] );
	for( int i = 1;i <= n;i ++ )
		scanf( "%d", &C[i] );
	sort( A + 1, A + n + 1 );
	sort( B + 1, B + n + 1 );
	sort( C + 1, C + n + 1 );
	int ipB = 1, ipC = 1, ans = 0;
	for( int i = 1;i <= n;i ++ ) {
		while( ipB <= n && B[ipB] <= A[i] ) ipB ++;
		while( ipC <= n && C[ipC] <= B[ipB] ) ipC ++;
		if( ipB > n || ipC > n ) break;
		else ans ++, ipB ++, ipC ++;
	}
	printf( "%d\n", ans );
	return 0;
}

C - 1, 2, 3 - Decomposition

结论:任何一个数最多不会由超过五个的123类数组成

暴力算每各位check1/2/3/4/5依次是否可以

#include <map>
#include <cstdio>
using namespace std;
#define int long long
map < int, int > mp;
int T, n;

int solve( int n ) {
	if( ! n ) return 0;
	if( mp[n] ) return mp[n];
	int s = n / 10, r = n % 10;
	if( 1 <= r && r <= 3 && solve( s ) <= 1 ) return mp[n] = 1;
	if( 2 <= r && r <= 6 && solve( s ) <= 2 ) return mp[n] = 2;
	if( 3 <= r && r <= 9 && solve( s ) <= 3 ) return mp[n] = 3;
	if( 4 <= r && r <= 9 && solve( s ) <= 4 ) return mp[n] = 4;
	if( 0 <= r && r <= 2 && solve( s - 1 ) <= 4 ) return mp[n] = 4;
	return mp[n] = 5;
}

signed main() {
	scanf( "%lld", &T );
	while( T -- ) {
		scanf( "%lld", &n );
		printf( "%lld\n", solve( n ) );	
	}
	return 0;
}

D - Inc, Dec - Decomposition

显然的定理:对于操作 i i i B i = B i − 1 / C i = C i − 1 B_i=B_{i-1}/C_i=C_{i-1} Bi=Bi1/Ci=Ci1二者中至少有一个是不变的

所以,一旦确定了 B 1 B_1 B1,两个序列都被确定下来,答案也就确定了

反转 C C C,重新定义为 A i = B i − C i A_i=B_i-C_i Ai=BiCi,那么 B , C B,C B,C序列的要求都变成了单调不下降

最后的答案反正是带绝对值的,这样的反转并不影响最后答案的统计,还是 ∑ i = 1 n ∣ B i ∣ + ∣ C i ∣ \sum_{i=1}^n|B_i|+|C_i| i=1nBi+Ci

A i + 1 > A i A_{i+1}>A_i Ai+1>Ai,原问题的解决方案肯定是增加 B B B,若 A i + 1 < A i A_{i+1}<A_i Ai+1<Ai,原问题的解决方案肯定是减少 C C C

原则上是没有变化的,但是改变 C C C后,全都变成了增加 B / C B/C B/C,操作可以表示为

  • B i + 1 = B i + max ⁡ ( A i + 1 − A i , 0 ) B_{i+1}=B_{i}+\max(A_{i+1}-A_i,0) Bi+1=Bi+max(Ai+1Ai,0)
  • C i + 1 = C i + max ⁡ ( A i − A i + 1 , 0 ) C_{i+1}=C_i+\max(A_i-A_{i+1},0) Ci+1=Ci+max(AiAi+1,0)

对于确定了 B 1 B_1 B1后的序列,每个 B i , C i B_i,C_i Bi,Ci都是 ∣ B 1 − k ∣ |B_1-k| B1k的形式,一共有 2 n 2n 2n k k k,答案显然是 B i B_i Bi k k k的中位数时最小

#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
#define int long long
#define maxn 200005
vector < int > ans;
int n;
int A[maxn];

int Fabs( int x ) {
	return x < 0 ? -x : x;
}

signed main() {
	scanf( "%lld", &n );
	for( int i = 1;i <= n;i ++ )
		scanf( "%lld", &A[i] );
	int B = A[1], C = 0;
	ans.push_back( B ), ans.push_back( C );
	for( int i = 1;i < n;i ++ ) {
		int x = A[i + 1] - A[i];
		if( x >= 0 ) B += x;
		else C -= x;
		ans.push_back( B );
		ans.push_back( C );
	}
	sort( ans.begin(), ans.end() );
	int ret = 0;
	for( int i = 0;i < ans.size();i ++ )
		ret += Fabs( ans[i] - ans[n] );
	printf( "%lld\n", ret );
	return 0;
}

E - Training

题目转录翻译一下就是求 ∑ i = 1 n [ A X + ⌊ i B X ⌋ = A Y + ⌊ i B Y ⌋ ] \sum_{i=1}^n\bigg[A_X+\lfloor\frac{i}{B_X}\rfloor=A_Y+\lfloor\frac{i}{B_Y}\rfloor\bigg] i=1n[AX+BXi=AY+BYi]

定义 f ( x ) = A X + x B X , g ( x ) = A Y + x B Y , F ( x ) = ⌊ f ( x ) ⌋ , G ( x ) = ⌊ g ( x ) ⌋ f(x)=A_X+\frac{x}{B_X},g(x)=A_Y+\frac{x}{B_Y},F(x)=\lfloor f(x)\rfloor,G(x)=\lfloor g(x)\rfloor f(x)=AX+BXx,g(x)=AY+BYx,F(x)=f(x),G(x)=g(x)

问题转化为求 ∑ i = 1 n [ F ( i ) = G ( i ) ] \sum_{i=1}^n\bigg[F(i)=G(i)\bigg] i=1n[F(i)=G(i)]

  • f ( x ) < g ( x ) − 1 ⇒ F ( x ) < G ( x ) f(x)<g(x)-1\Rightarrow F(x)<G(x) f(x)<g(x)1F(x)<G(x)

  • g ( x ) − 1 ≤ f ( x ) ≤ g ( x ) ⇒ F ( x ) = { G ( x ) − 1 , G ( x ) } g(x)-1\le f(x)\le g(x)\Rightarrow F(x)=\bigg\{G(x)-1,G(x)\bigg\} g(x)1f(x)g(x)F(x)={G(x)1,G(x)}

    • g ( x ) − 1 ≤ f ( x ) g(x)-1\le f(x) g(x)1f(x)

      A Y + x B Y − 1 ≤ A X + x B X ⇔ A Y B Y B X + x B X − B X B Y ≤ A X B Y B X + x B Y A_Y+\frac{x}{B_Y}-1\le A_X+\frac{x}{B_X}\Leftrightarrow A_YB_YB_X+xB_X-B_XB_Y\le A_XB_YB_X+xB_Y AY+BYx1AX+BXxAYBYBX+xBXBXBYAXBYBX+xBY

      ⇔ ( A Y − A X − 1 ) B X B Y ≤ x ( B Y − B X ) ⇔ ( A Y − A X − 1 ) B X B Y B Y − B X ≤ x \Leftrightarrow (A_Y-A_X-1)B_XB_Y\le x(B_Y-B_X)\Leftrightarrow \frac{(A_Y-A_X-1)B_XB_Y}{B_Y-B_X}\le x (AYAX1)BXBYx(BYBX)BYBX(AYAX1)BXBYx

    • f ( x ) ≤ g ( x ) f(x)\le g(x) f(x)g(x)

      ( A Y − A X ) B X B Y B Y − B X ≥ x \frac{(A_Y-A_X)B_XB_Y}{B_Y-B_X}\ge x BYBX(AYAX)BXBYx

  • g ( x ) < f ( x ) ≤ g ( x ) + 1 ⇒ F ( x ) = { G ( x ) , G ( x ) + 1 } g(x)<f(x)\le g(x)+1\Rightarrow F(x)=\bigg\{G(x),G(x)+1\bigg\} g(x)<f(x)g(x)+1F(x)={G(x),G(x)+1}

    • g ( x ) < f ( x ) g(x)<f(x) g(x)<f(x)

      ( A Y − A X ) B X B Y B Y − B X < x \frac{(A_Y-A_X)B_XB_Y}{B_Y-B_X}< x BYBX(AYAX)BXBY<x

    • f ( x ) < g ( x ) + 1 f(x)<g(x)+1 f(x)<g(x)+1

      ( A Y − A X + 1 ) B X B Y B Y − B X > x \frac{(A_Y-A_X+1)B_XB_Y}{B_Y-B_X}> x BYBX(AYAX+1)BXBY>x

  • g ( x ) + 1 < f ( x ) ⇒ F ( x ) > G ( x ) g(x)+1<f(x)\Rightarrow F(x)>G(x) g(x)+1<f(x)F(x)>G(x)

只有两种情况才可能出现 F ( x ) = G ( x ) F(x)=G(x) F(x)=G(x),并且可以数学化的解出 f ( x ) f(x) f(x)的范围

在已知范围 [ l , r ] [l,r] [l,r]内,可以巧妙转化, ∑ i = l r [ F ( i ) = G ( i ) ] ⇔ ( r − l + 1 ) − ∣ ∑ x = l r A X + ⌊ x B X ⌋ − ∑ x = l r A Y + ⌊ x B Y ⌋ ∣ \sum_{i=l}^r\bigg[F(i)=G(i)\bigg]\Leftrightarrow (r-l+1)-\bigg|\sum_{x=l}^rA_X+\lfloor\frac{x}{B_X}\rfloor-\sum_{x=l}^{r}A_Y+\lfloor\frac{x}{B_Y}\rfloor\bigg| i=lr[F(i)=G(i)](rl+1)x=lrAX+BXxx=lrAY+BYx

差分地计算 ∑ x = l r A X + ⌊ x B X ⌋ \sum_{x=l}^rA_X+\lfloor\frac{x}{B_X}\rfloor x=lrAX+BXx

∑ x = 1 n a + ⌊ x b ⌋ = b ∗ ( a + a + ⌊ n b ⌋ − 1 ) ∗ ⌊ x b ⌋ 2 + ( n − ⌊ n b ⌋ ∗ b + 1 ) ∗ ( a + ⌊ x b ⌋ ) \sum_{x=1}^na+\lfloor\frac{x}{b}\rfloor=b*\frac{(a+a+\lfloor\frac{n}{b}\rfloor-1)*\lfloor\frac{x}{b}\rfloor}{2}+(n-\lfloor\frac{n}{b}\rfloor*b+1)*(a+\lfloor\frac{x}{b}\rfloor) x=1na+bx=b2(a+a+bn1)bx+(nbnb+1)(a+bx)

#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;
#define int long long
#define eps 1e-8

int calc( int a, int b, int n ) {
	int t = ( n + 1 ) / b;
	return ( a * 2 + ( t - 1 ) ) * t * b / 2 + ( a + t ) * ( n - t * b + 1 );
}

signed main() {
	int T, n, AX, AY, BX, BY;
	scanf( "%lld", &T );
	long double L, R; int l, r, ans, cnt;
	while( T -- ) {
		scanf( "%lld %lld %lld %lld %lld", &n, &AX, &BX, &AY, &BY );
		if( BX == BY ) {
			if( AX == AY ) printf( "%lld\n", n );
			else printf( "0\n" );
			continue;
		}
		if( BX > BY ) swap( AX, AY ), swap( BX, BY );
		ans = 0;
		//g(x)-1<=f(x)<=g(x)
		L = 1.0 * ( AY - AX - 1 ) * BX * BY / ( BY - BX ) + eps;
		R = ( AY - AX ) * 1.0 * BX * BY / ( BY - BX );
		if( L < 1 ) l = 1;
		else l = ceil( L );
		if( R > n ) r = n;
		else r = floor( R );
		r = max( r, l - 1 );
		cnt = calc( AY, BY, r ) - calc( AY, BY, l - 1 ) - calc( AX, BX, r ) + calc( AX, BX, l - 1 );
		ans += r - l + 1 - cnt;
		//g(x)<f(x)<g(x)+1
		L = R + eps;
		R = ( AY - AX + 1 ) * 1.0 * BX * BY / ( BY - BX ) - eps;
		if( L < 1 ) l = 1;
		else l = ceil( L );
		if( R > n ) r = n;
		else r = floor( R );
		r = max( r, l - 1 );
		cnt = calc( AX, BX, r ) - calc( AX, BX, l - 1 ) - calc( AY, BY, r ) + calc( AY, BY, l - 1 );
		ans += r - l + 1 - cnt;
		
		printf( "%lld\n", ans );
	} 
	return 0;
} 

F - Insert Addition

数列的生成类比斯坦纳树

因为 a , b a,b a,b的范围,迭代次数永远小于生成数的大小,因此考虑充分迭代多次后保留 ≤ n \le n n的数

如果 ( x 1 , y 1 ) , ( x 2 , y 2 ) (x_1,y_1),(x_2,y_2) (x1,y1),(x2,y2)在系数数列中相邻,则有 x 1 y 2 − x 2 y 1 = 1 x_1y_2-x_2y_1=1 x1y2x2y1=1

并且只要坐标都 > 0 >0 >0,那么总有一个时刻在系数数列中有且仅出现一次

这是个欧几里得形式的式子,当且仅当 ( a , b ) = 1 (a,b)=1 (a,b)=1才有解

把数列当成斯坦纳树跑成线段树, ( i , j ) ← ( i − 1 , j − 1 ) + ( i − 1 , j + 1 ) (i,j)\leftarrow (i-1,j-1)+(i-1,j+1) (i,j)(i1,j1)+(i1,j+1)

g c d ( a , b ) = 1 ⇒ i ∗ a + b ∗ j ≤ n gcd(a,b)=1\Rightarrow i*a+b*j\le n gcd(a,b)=1ia+bjn,就是莫比乌斯反演了,暴力枚举 i i i暴力算

#include <cstdio>
#define int long long
#define maxn 300005
int mu[maxn], prime[maxn];
bool vis[maxn];
int a, b, n, l, r;

void init() {
	int cnt = 0;
	mu[1] = 1;
	for( int i = 2;i <= n;i ++ ) {
		if( ! vis[i] ) prime[++ cnt] = i, mu[i] = -1;
		for( int j = 1;j <= cnt && i * prime[j] <= n;j ++ ) {
			vis[i * prime[j]] = 1;
			if( i % prime[j] == 0 ) break;
			else mu[i * prime[j]] = -mu[i];
		}
	}
}

void print( int x ) {
	if( l > r || x > n ) return;
	else if( l == 1 ) printf( "%lld ", x ), r --;
	else l --, r --;
}

int calc( int x, int y ) {
	int cnt = 0;
	for( int i = 1;x + y <= n / i;i ++ ) {
		if( ! mu[i] ) continue;
		for( int j = 1;x * j + y <= n / i;j ++ )
			cnt += mu[i] * ( n / i - x * j ) / y;
	}
	return cnt;
}

void print_all( int x, int y ) {
	if( x + y > n ) return;
	print_all( x, x + y );
	print( x + y );
	print_all( x + y, y );
}

void dfs( int x, int y ) {
	int cnt = calc( x, y );
	if( l > r || ! cnt ) return;
	if( l > cnt ) {
		l -= cnt, r -= cnt;
		return;
	}
	if( l == 1 && cnt <= r ) {
		print_all( x, y );
		return;
	}
	dfs( x, x + y );
	print( x + y );
	dfs( x + y, y );
}

signed main() {
	scanf( "%lld %lld %lld %lld %lld", &a, &b, &n, &l, &r );
	init();
	print( a ), dfs( a, b ), print( b );
	return 0;
}
  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值