Codeforces Round #775 (Div. 2)

Codeforces Round #775 (Div. 2)

D. Integral Array

题目大意:给定n(<=1e6)个数,数的范围是在1-c(<=1e6)中,如果其中任意两个数x,y,(x>=y),
使得x/y(下取整)也在n个数里面就是好的数列,判断这个n个数是不是好的数列

x/y = z, 因为x和y的大小都是1e6的数量级的,暴力枚举肯定会寄,因为x的最大值是c也就是1e6,
我们可以枚举y,z,当固定y的时候,y,2y,3y....ty<=c,所以就是枚举c/y次,所以最多也就是c/1+c/2+...c/c=c*logc大小的枚举,
那么枚举完y,z,该如果判断呢,就是y在数列中出现过,z没有在数列中出现过,
却存在一个x使得x/y=z,这个x其实就是范围在[y*z, y*z+z-1]的数,我们可以用一个前缀和判断这个区间有没有出现过数

#include<bits/stdc++.h>

using namespace std;
typedef long long LL;
const int N = 2e6+10;
int a[N];
int st[N];
int s[N];

int main(){
	int T;
	cin >> T;
	while(T--){
		int n, c;
		scanf("%d %d", &n, &c);
		for(int i = 1; i <= 2*c; i ++) st[i] = s[i] = 0;
		for(int i = 1; i <= n; i++) scanf("%d", &a[i]), st[a[i]] = 1;

		for(int i = 1; i <= 2*c; i ++) s[i] = s[i-1] + st[i];
		int flag = 1;
		for(int i = 1; i <= c; i ++){
			if(!st[i]) continue;
			for(int j = 1; j * i <= c ; j++){
				if(st[j]) continue;
				if(s[i * j + i - 1] - s[i * j - 1] != 0) flag = 0;
				// cout << i << ' ' << j << endl;
			}
		}
		if(!flag) puts("No");
		else puts("Yes");
	}
	return 0;
}

E. Tyler and Strings

题目大意:给定一个长度为n(<=200000)和m(<=200000)的数列a和b,问存在多少种a的排列字典序比b小

从前往后依次看b的每一位,然后判断a咋放
当现在枚举到了b的第i位,也就是现在是b[i]
那么当我们在对应的位置a放一个比b[i]小的数的话,后面的数就是随便放了,现在问题就是求这种情况的案
C(现在a中没有摆放的数的个数,现在a中没有摆放的数且比b[i]小的个数)*(现在a中没有摆放的数的个数-1的全
排列)/(对重复元素的去重,比如待摆放的元素有两个3,就是/2!)
假设现在摆放的是b[i]的话,我们更新(使用树状数组)一些要记录的元素继续进行计算就可以了

#include<bits/stdc++.h>

using namespace std;
typedef long long LL;
const int N = 2e5+10, mod = 998244353;
int tr[N], a[N], b[N];
int f[N];

int lowbit(int x){
	return x & -x;
}

void add(int a, int x){
	for(int i = a; i <= 2e5; i+=lowbit(i)) tr[i] += x; 
}

int sum(int a){
	int sum = 0;
	for(int i = a; i; i -= lowbit(i)) sum += tr[i];
	return sum;
}

LL qmi(LL a, LL b, LL mod){
	LL res = 1;
	while(b){
		if(b&1) res = res * a % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return res;
}

int main(){
	int n, m;
	cin >> n >> m;
	f[0] = 1;
	for(int i = 1; i <= n; i ++) f[i] = (LL)f[i-1] * i % mod;
	for(int i = 1; i <= n; i++) scanf("%d", &a[i]), add(a[i], 1);
	for(int j = 1; j <= m; j++) scanf("%d", &b[j]);


	LL down = 1;
	for(int i = 1; i <= 2e5; i++){
		down = (LL)down * f[sum(i)-sum(i-1)] % mod;
	}
	// cout << down << endl;

	LL res = 0;
	for(int i = 1; i <= m; i++){
		int cnt = sum(b[i]-1);
		res = (res + (LL)cnt * f[n-i] % mod * qmi(down, mod-2, mod) % mod) % mod;
		int cntb = sum(b[i]) - cnt;
		if(cntb == 0 && i == n + 1){
			res ++;
			break;
		}
		else if(cntb == 0) break;
		add(b[i], -1);
		down = (LL)down * f[cntb - 1] % mod * qmi(f[cntb ], mod-2, mod) % mod;
	}
	cout << res%mod << endl;

	return 0;
}

posted @ 2022-03-12 18:49  牛佳文  阅读(55)  评论(0编辑  收藏  举报