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;
}