20261008做题记录
上午模拟赛
T1:
简单题,我们发现我们可以找出每个下标最大是多少,然后因为每个集合都必须要有最大值 \(c\) 所以最大值 \(c\) 所提供的方案数就是所有要求最大数是 \(c\) 交集的数且它的最大值可以是 \(c\) 的数量,令其为 \(tot_c\),令最大值大于等于 \(c\) 的为 \(cnt_c\),考虑从大到小填入数,那么分两种情况:
1. 该值没有成为最大值
那么提供的方案数就是 \(cnt_c - (n-c)\),如果是负的无解。
2.该值是最大值
那么提供的方案数就是 \(tot_c\) 如果为 \(0\) 则无解。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define N 1000005
#define intl long long
#define mod (998244353)
#define For(i,a,b) for(intl i=a;i<=b;i++)
#define deo(i,a,b) for(intl i=a;i>=b;i--)
intl read() {
intl x=0,k=1;char ch=getchar();
while(!isdigit(ch)) {if(ch == '-') k=-1;ch=getchar();}
while(isdigit(ch)) {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*k;
}
intl fac[N], inv[N];
intl Fpow(intl a,intl b) {intl res=1;for(;b;b>>=1,(a*=a)%=mod) if(b&1) (res*=a)%=mod;return res;}
intl A(intl n,intl m) {
if(m > n || m < 0) return 0ll;
return fac[n]*inv[n-m]%mod;
}
intl n, m, a[N], cnt[N], vis[N], now[N];
vector<intl> vec[N];
void solve() {
n = read(), m = read();
For(i,1,n) a[i] = n;
For(i,1,m) {
intl k = read(), c = read();
vector<intl> qwe;
while(k --) {
intl x = read();
qwe.push_back(x), now[x] = i, a[x] = min(a[x], c);
}
if(!vis[c]) vec[c] = qwe, vis[c] = 1;
else {
vector<intl> qaz;
qaz.clear();
for(auto x:vec[c]) if(now[x] == i) qaz.push_back(x);
vec[c] = qaz;
}
}
For(i,1,n) cnt[a[i]] ++;
deo(i,n,1) cnt[i] += cnt[i+1];
intl ans = 1;
deo(i,n,1) {
// cout << i <<" " << n-i << " " << cnt[i] <<endl;
if(cnt[i] - (n - i) <= 0) return puts("0"), void();
if(!vis[i]) (ans *= cnt[i]-(n-i)) %= mod;
else {
intl tot = 0;
for(auto x:vec[i]) if(a[x] == i) tot ++;
(ans *= tot) %= mod;
}
}
printf("%lld\n", ans);
}
void clear() {
For(i,1,n) a[i] = cnt[i] = vis[i] = now[i] = 0, vec[i].clear();
}
int main() {
// freopen("sample2.in","r",stdin);
fac[0] = 1;
For(i,1,N-5) fac[i] = fac[i-1]*i%mod;
inv[N-5] = Fpow(fac[N-5], mod-2);
deo(i,N-6,0) inv[i] = inv[i+1]*(i+1)%mod;
intl T = read();
while(T --) solve(), clear();
return 0;
}
T2:
不会(会n^2。
T3:
不会。
T4:
不会。
CF1251D
简单题,显然二分答案,然后考虑如何check,我们令当前check的答案为 \(x\),大于等于 \(x\) 的数量为 \(cnt\),对于 \(r \lt x\) 的员工,因为他不可能等于 \(x\) 所以我们取 \(l\) 节省钱, \(x \lt l\) 的员工同理,取 \(l\),然后 \(cnt + 1\),我们考虑剩下在的数,因为我们要考虑让 \(\lceil \frac{n}{2} \rceil \le cnt\) 且钱越小越好,所以我们考虑让 \(l\) 大的工资为 \(x\) 一直到满足条件为止,然后再把剩下的员工工资取 \(l\) 就行,因为 \(x\) 已经是中位数,所以剩下的取最小值就可以了。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define N 200005
#define intl long long
#define For(i,a,b) for(intl i=a;i<=b;i++)
#define deo(i,a,b) for(intl i=a;i>=b;i--)
intl read() {
intl x=0,k=1;char ch=getchar();
while(!isdigit(ch)) {if(ch == '-') k=-1;ch=getchar();}
while(isdigit(ch)) {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*k;
}
intl n, s, tmp[N];
pair<intl,intl> a[N];
bool check(intl x) {
intl cnt = 0, sum = 0, tot = 0;
For(i,1,n) {
if(a[i].second < x) sum += a[i].first;
else if(a[i].first > x) cnt ++, sum += a[i].first;
else tmp[++tot] = i;
}
while(tot && cnt < (n+1)/2) sum += x, tot --, cnt ++;
if(cnt < (n+1)/2) return 0;
For(i,1,tot) sum += a[tmp[i]].first;
return s >= sum;
}
void solve() {
n = read(), s = read();
For(i,1,n) a[i].first = read(), a[i].second = read();
sort(a+1,a+n+1);
intl l = 0, r = (s+(n+1)/2-1)/((n+1)/2), ans = -1;
while(l <= r) {
intl mid = (l+r)>>1;
// cout << mid << " " << l << " " << r << endl;
if(check(mid)) ans = mid, l = mid+1;
else r = mid-1;
}
printf("%lld\n", ans);
}
void clear() {
For(i,1,n) a[i] = {0, 0};
}
int main() {
intl T = read();
while(T --) solve(), clear();
return 0;
}
/*
1
19 1175
44 87
68 100
93 98
76 79
10 58
74 99
87 97
23 75
62 73
100 100
71 76
73 87
76 82
44 84
54 90
2 82
67 99
85 97
66 88
*/

浙公网安备 33010602011771号