Codeforces Round #708 (Div. 2) A - C ,E1

A - Meximization

因为要整个序列的 M E X MEX MEX最大,我们就先把能连续排好序的排出来,这样可以保证最后重复出现的 M E X MEX MEX是最大的,所以就是排个序再把重复的放后面。

#include <bits/stdc++.h>

using namespace std;

#define pb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;
const int N = 1e3 + 7;
multiset<int>a,b;
// int a[N],b[N];

int main() {
	int T;scanf("%d",&T);
	while(T--) {
		a.clear();b.clear();
		int n,x;scanf("%d",&n);
		for(int i = 1;i <= n;i ++) {
			scanf("%d",&x);
			if(a.count(x)) b.insert(x);
			else a.insert(x);
		}
		for(multiset<int>::iterator it = a.begin();it != a.end();it ++) {
			printf("%d ",*it);
		}
		for(multiset<int>::iterator it = b.begin();it != b.end();it ++) {
			printf("%d ",*it);
		}
		puts("");
	}
	return 0;
}

B - M-arrays

操作的关键就是找的是 k ∗ m , ( k = 1 , 2 , . . , n ) k * m,(k =1,2,..,n) km,(k=1,2,..,n)所以我们可把每个 a i a_i ai取余,这样所有数都可以放在 [ 0 , m − 1 ] [0,m-1] [0,m1]来统计,题目数据 a i ≥ 1 a_i \geq 1 ai1,所以0仅仅代表 k ∗ m k*m km而已,然后每次都对形如 ( x , m − x ) (x,m-x) (x,mx)这样的一对数去统计 x x x m − x m-x mx的个数,就可以计算出答案了。

#include <bits/stdc++.h>

using namespace std;

#define pb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;
int cnt[100010];

int main() {
	int T;scanf("%d",&T);
	while(T--) {
		int n,m,x;
		scanf("%d%d",&n,&m);
		for(int i = 1;i <= n;i ++) {
			scanf("%d",&x);
			x %= m;
			cnt[x]++;
		}
		int ans = 0;
		if(cnt[0]) ans++;
		for(int i = 1;i <= m/2;i ++) {
			if(cnt[i] || cnt[m-i]) {
				if(cnt[i] == cnt[m-i]) ans++;
				else ans += abs(cnt[i]-cnt[m-i]);
			}
		}
		printf("%d\n",ans);
		for(int i = 0;i <= m;i ++) cnt[i] = 0;//别忘了0
	}
	return 0;
}

C1 - k-LCM (easy version)

分成3个数。
1. 1. 1.如果n是奇数,那么就是直接 n / 2 , n / 2 , 1 n/2,n/2,1 n/2,n/2,1构造。
2. 2. 2.如果n的偶数
a . n / 2 a.n/2 a.n/2是奇数,那么 n / 2 − 1 , n / 2 − 1 , 2 n/2-1,n/2-1,2 n/21,n/21,2构造,因为前面两个数肯定是偶数。
b . n / 2 b.n/2 b.n/2是偶数,那么 n / 2 , n / 4 , n / 4 n/2,n/4,n/4 n/2,n/4,n/4构造。

#include <bits/stdc++.h>

using namespace std;

#define pb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;
//构造题 利用前一问的3 直接多的全补1 剩余部分用3构造
int main() {
	int T;scanf("%d",&T);
	while(T--) {
		int n,k;
		scanf("%d%d",&n,&k);
		int cnt = k % 3 + k - (k % 3) - 3;
		for(int i = 1;i <= cnt;i ++) {
			printf("1 ");
		}
		n -= cnt;
		if(n == 3) { 
			printf("1 1 1\n");
			continue;
		}
		if(n == 4) {
			printf("2 1 1\n");
			continue;
		}
		if(n & 1) printf("1 %d %d\n",n/2,n/2);
		else {
			if((n / 2) & 1) {
				printf("2 %d %d\n",n/2-1,n/2-1);
			}
			else {
				printf("%d %d %d\n",n/2,n/4,n/4);
			}
		}
	}
	return 0;
}

C2 - k-LCM (hard version)

有上一题我们知道一个数肯定能被分为3部分,那么我们把超过3的部分用1去填充,剩下的数再分成3份不就好了。

#include <bits/stdc++.h>

using namespace std;

#define pb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;
//构造题 利用前一问的3 直接多的全补1 剩余部分用3构造
int main() {
	int T;scanf("%d",&T);
	while(T--) {
		int n,k;
		scanf("%d%d",&n,&k);
		int cnt = k % 3 + k - (k % 3) - 3;
		for(int i = 1;i <= cnt;i ++) {
			printf("1 ");
		}
		n -= cnt;
		if(n == 3) { 
			printf("1 1 1\n");
			continue;
		}
		if(n == 4) {
			printf("2 1 1\n");
			continue;
		}
		if(n & 1) printf("1 %d %d\n",n/2,n/2);
		else {
			if((n / 2) & 1) {
				printf("2 %d %d\n",n/2-1,n/2-1);
			}
			else {
				printf("%d %d %d\n",n/2,n/4,n/4);
			}
		}
	}
	return 0;
}

E1 - Square-free division (easy version) (数学 + 小思维)

这道题要考虑唯一分解定理,我们知道如果一个数是完全平方数,那么这个数的各个素因子的幂次一定是偶数。

也考虑怎么分割序列,因为题目要求分割的子序列必须是连续的,那么我们就从 i = 1 i = 1 i=1开始 O ( n ) O(n) O(n)的就能分完,现在就需要考虑怎么得到当前区间内是否有两个数能组成完全平方数。

由唯一分解定理,我们可以对每个 a i a_i ai统计它的素因子幂次为奇数的素因子的乘积,这里还有个操作就是,我们只考虑奇偶性,所以对 q 1 p 1 , q 2 p 2 , . . . . . , q n p n {q_1}^{p_1},{q_2}^{p_2},.....,{q_n}^{p_n} q1p1,q2p2,.....,qnpn要把他们变成 q 1 p 1 % 2 , q 2 p 2 % 2 , . . . . . , q n p n % 2 {q_1}^{p_1 \%2},{q_2}^{p_2\%2},.....,{q_n}^{p_n\%2} q1p1%2,q2p2%2,.....,qnpn%2,这样来考虑。然后如果这个乘积在之前的序列中出现过,就证明这两个数就能互补所有的奇数幂次素因子从而形成完全平方数,这时把前面的记录答案清空即可,答案加1,往后走即可。

对于每个 a i a_i ai分解的所有素因子,可以在筛素数的维护一下,每个数的最小素因子是谁,然后不断除这个最小素因子即可,如果直接枚举所有素数会超时的。

#include <bits/stdc++.h>

using namespace std;

#define pb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;
//由唯一分解定理得 如果 x*y是完全平方数 那么他的每个素因子的幂次一定是偶数 可以利用这个性质判断区间内是否出现不合法的数对
int prime[1000010],tot,vis[10000010];
void Prime() {
	for(ll i = 2;i < 10000010;i ++) {
		if(!vis[i]) {
			prime[++tot] = i;
			vis[i] = i;
		}
		for(ll j = 1;j <= tot && prime[j] * i < 10000010;j ++) {
			vis[prime[j] * i] = prime[j];
			if(i % prime[j] == 0) break;
		}
	}
}
int a[200010];
std::unordered_map<int,int>mp,fac;
inline int solve(int x) {//直接枚举素数找素因子找会超时 筛素数的时候记录一下 当前数的最小素因子是谁 这样最多做20多次就可以分解完毕
	if(x == 1) return 1;
	int tmp = x,res = 1;
	while(tmp != 1) {
		int t = vis[tmp],cnt = 0;
		while(vis[tmp] == t) {
			tmp /= t;
			cnt++;
		}
		if(cnt & 1) res *= t;
	}
	return res;
}
//看出现次数为奇数的素因子的乘积 如果这个值在前面出现过 那么那两个数就能组成完全平方数 把幂次都mod2
int main() {
	Prime();
	int T;scanf("%d",&T);
	while(T--) {
		mp.clear();
		int n,k;
		scanf("%d%d",&n,&k);
		for(int i = 1;i <= n;i ++) scanf("%d",&a[i]);
		int ans = 0;
		for(int i = 1;i <= n;i ++) {
			int tmp = solve(a[i]);
			if(mp[tmp]) {
				ans++;
				mp.clear();
				mp[tmp]++;
			}
			else {
				mp[tmp]++;
			}
		}
		ans++;
		printf("%d\n",ans);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值