【题解】CF2008G

题意翻译

原题链接CF2008G
在这里插入图片描述

思路

  由于操作次数不限,观察到所有操作都是可逆的,所以可以随便搞。然后观察mex函数,发现让所有数在不重复的情况下尽可能地小是最优的(重复就浪费了)。
  
  先不考虑重复和 0 0 0,对于 a 1 , a 2 , . . . a n a_{1}, a_{2},...a_{n} a1,a2,...an,经过无限次互相作差后,由欧几里得算法可知, g c d ( x , y ) = g c d ( x , y − x ) gcd(x, y) = gcd(x, y-x) gcd(x,y)=gcd(x,yx),令 g = g c d ( a 1 , . . . a n ) g=gcd(a_{1},...a_{n}) g=gcd(a1,...an),这些数最终会变成 n n n g g g
  
  然后再调整,避免重复。当 n ≠ 1 n \neq 1 n=1,让两个 g g g相减得到 0 0 0,再把其他多余的 g g g逐个加上去,最终变成 0 , g , . . . , ( n − 1 ) g 0, g, ..., (n-1)g 0,g,...,(n1)g。当 n = 1 n=1 n=1,动不了,特判即可。
  
  最后,计算第 k k k个未出现过的数,观察到 i g ig ig ( i + 1 ) g (i+1)g (i+1)g之间由 g − 1 g-1 g1个数未出现,所以令 m = k / ( g − 1 ) m = k / (g-1) m=k/(g1),即可定位到需要的数大致的位置然后分情况讨论:

  (1) n = = 1 n==1 n==1 g > k − 1 g > k-1 g>k1 ,直接取 0 → k − 1 0 \to k-1 0k1即可。
  (2) n = = 1 n==1 n==1 g ≤ k − 1 g \le k-1 gk1,取 0 , 1 , . . . g − 1 , g + 1 , . . . , k 0, 1, ... g-1, g+1, ..., k 0,1,...g1,g+1,...,k
  (3) g = = 1 g==1 g==1, 直接输出 k − 1 + n k-1+n k1+n。这里特判是为了防止后续计算中 g − 1 = 0 g-1=0 g1=0
  (4) n > 1 n>1 n>1, m > n − 1 m > n-1 m>n1,说明已有的数全部被用上了,直接输出 n + k − 1 n+k-1 n+k1
  (5) n > 1 n>1 n>1, m ≤ n − 1 m \le n-1 mn1, m ∗ ( g − 1 ) = = k m * (g-1) == k m(g1)==k,说明恰好填满空隙,输出 k + m − 1 k+m-1 k+m1
  (6) n > 1 n>1 n>1, m ≤ n − 1 m \le n-1 mn1, m ∗ ( g − 1 ) ≠ k m * (g-1) \neq k m(g1)=k,输出k+m。

  分类有点繁琐,可能有几类可以通过一个式子表达。

代码

#include<bits/stdc++.h>
#define N 200005
using namespace std;
int t, n, k, a[N];
int gcd(int x, int y) {
	if(y == 0) return x;
	return gcd(y, x%y);
}
int main() {
	cin>>t;
	while(t--) {
		cin>>n>>k;
		for(int i=1;i<=n;i++) cin>>a[i];
		int g = a[1];
		for(int i=2;i<=n;i++) g = gcd(g, a[i]);
		// 最优0, g, 2g, ..., (n-1)g   (n != 1)
		if(n == 1) {
			if(g > k-1) cout<<k-1<<endl;
			else cout<<k<<endl;
		} else if(g != 1){
			int m = k / (g-1);  //填满m个间隙 
			if(m > n-1) {
				cout<<k-1+n<<endl;
			} else {
				if(m * (g-1) == k){   // 恰好 
					cout<<k+m-1<<endl;
				} else {
					cout<<k+m<<endl;
				}
			}
		} else {
			// 0, 1, 2, ..., n-1
			cout<<k-1+n<<endl;
		}
	}
} 
  • 13
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值