多校A层冲刺NOIP2024模拟赛18

赛时电脑死了,恼了就没交。赛后交是155pts。

T1 是二分答案+三维前缀和check,T2 瞎写了个搜索。

T1 选彩笔(rgb)

将r,g,b看做三个维度。

答案显然有可二分性,直接二分答案。那么就转化为是否存在一个边长为\(mid\)三维正方体,其内部有大于\(k\)个点。

三维前缀和维护即刻,时间复杂度是\(O(V^3\log V)\)的。

但貌似三维偏序也能做,只是非常非常麻烦?(雾)

点此查看代码
#include <bits/stdc++.h>
using namespace std ; 
#define rep(i,s,t,p) for(int i = s;i <= t;i += p)
#define drep(i,s,t,p) for(int i = s;i >= t;i -= p)
#ifdef LOCAL
    FILE *InFile = freopen("in.in","r",stdin),*OutFile = freopen("out.out","w",stdout);
    // FILE *ErrFile = freopen("err.err","w",stderr);
#else
    FILE *InFile = freopen("rgb.in","r",stdin),*OutFile = freopen("rgb.out","w",stdout);
#endif
using ll = long long;using ull = unsigned long long;
using db = double;using ldb = long double;
const int N = 1e5 + 100,V = 257;
struct Node {int r,g,b;}a[N];
int n,K,maxn[3],sum[V][V][V],VA = 256;
inline int P(int x){return x < 0? 0:x;}
inline int val(int i , int j , int k , int mid){
	return sum[i][j][k]-sum[P(i-mid-1)][j][k]-
			sum[i][P(j-mid-1)][k]-sum[i][j][P(k-mid-1)]+
			sum[P(i-mid-1)][P(j-mid-1)][k]+sum[P(i-mid-1)][j][P(k-mid-1)]+
			sum[i][P(j-mid-1)][P(k-mid-1)]-sum[P(i-mid-1)][P(j-mid-1)][P(k-mid-1)];
}
inline bool check(int mid) {
	rep(i,1,VA,1) rep(j,1,VA,1) rep(k,1,VA,1)
		if (val(i,j,k,mid) >= K) return true;
	return false ; 
}
inline void solve(){
	cin>>n>>K;
	rep(i,1,n,1){
		cin>>a[i].r>>a[i].g>>a[i].b;
		a[i].r++,a[i].b++,a[i].g++;
		maxn[0] = max(maxn[0],a[i].r),maxn[1] = max(maxn[1],a[i].g),maxn[2] = max(maxn[2],a[i].b);
		sum[a[i].r][a[i].g][a[i].b]++;
	}
	rep(i,1,VA,1) rep(j,1,VA,1) rep(k,1,VA,1)
		sum[i][j][k] += (sum[i-1][j][k]+sum[i][j-1][k]+sum[i][j][k-1]-sum[i][j-1][k-1]-sum[i-1][j][k-1]-sum[i-1][j-1][k]+sum[i-1][j-1][k-1]);
	int l = 1,r = 256,ans = 0;
	while(l <= r){
		int mid = (l + r) >> 1;
		if (check(mid)) ans = mid,r = mid - 1;
		else l = mid + 1 ; 
	}
	cout<<ans<<'\n';
}
signed main() {
	cin.tie(nullptr)->sync_with_stdio(false);
	solve();
}

T2 兵蚁排序(sort)

考虑排序的性质是减少序列中的逆序对,且不会新增逆序对。

然后如果\(A\)中有的逆序对而\(B\)中没有,那么就将这俩swap一下,冒泡即可,时间复杂度\(O(n^2)\)

点此查看代码
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,t,p) for(int i = s;i <= t;i += p)
#define drep(i,s,t,p) for(int i = s;i >= t;i -= p)
#ifdef LOCAL
    FILE *InFile = freopen("in.in","r",stdin),*OutFile = freopen("out.out","w",stdout);
    // FILE *ErrFile = freopen("err.err","w",stderr);
#else
    FILE *InFile = freopen("sort.in","r",stdin),*OutFile = freopen("sort.out","w",stdout);
#endif
using ll = long long;using ull = unsigned long long;
using db = double;using ldb = long double;
const int N = 1e3 + 10;
int n,a[N],b[N];
#define pii pair<int,int>
#define mk make_pair
vector<pii> ans;
int cta[N],ctb[N];
inline void solve(){
    cin>>n;vector<pii>().swap(ans);
    rep(i,1,n,1) cta[i] = ctb[i] = 0;
    rep(i,1,n,1) cin>>a[i];rep(i,1,n,1) cin>>b[i];
    bool flag = true;
    rep(i,1,n,1){
        if(!flag) break;
        ctb[b[i]]++;
        int j = 1,k = 0;
        while(j <= n){
            if(a[j] == b[i]) k++;
            if(k == ctb[b[i]]) break;
            j++;
        }
        drep(k,j-1,max(ctb[b[i]],i),1){
            if(a[k] > a[k + 1]){
                ans.push_back(mk(k,k+1));
                swap(a[k],a[k+1]);
            }
            else{
                flag = false;break;
            }
        }
    }
    if(!flag) cout<<"-1\n";
    else{
        cout<<"0\n"<<ans.size()<<'\n';
        for(auto i:ans) cout<<i.first<<' '<<i.second<<'\n';
    }
}
signed main(){
    cin.tie(nullptr)->sync_with_stdio(false);
    int T;cin>>T;while(T--) solve();
}

T3 人口局 DBA(dba)

容斥。

\(f_{i,j}\)表示已经当前已经填了\(i-1\)个数,和为\(j\)的方案数。

有容斥柿子为\(f_{i,j}=\sum\limits_{k=0}^i(-1)^k\mathrm{C}_i^k\mathrm{C}_{j+i-km-1}^{i-1}\)

答案为\(\sum\limits_{i=1}^n\sum\limits_{j=0}^{a_i-1}f_{n-i,s_i-j}\),其中\(s_i\)表示\(a\)的后缀和。

将这个柿子拆开,有

\[\sum_{i=1}^n\sum_{j=0}^{a_i-1}\sum_{k=0}^{n-i}(-1)^k\mathrm{C}_{n-i}^k\mathrm{C}_{s_i-j-km-1+n-i,n-i-1} \]

转化一下就是

\[\sum_{i=1}^n\sum_{k=0}^{n-i}(-1)^k\mathrm{C}_{n-i}^k\sum_{j=0}^{a_i-1}\mathrm{C}_{s_i-km+n-i-1-j}^{n-i-1} \]

发现后面的\(s_i-km,n-i-1\)是个常量,所以后面的柿子等价于求

\[\sum_{i=0}^p\mathrm{C}_{n+m-i}^m \]

将这玩意扔到杨辉三角上,然后画一下图,推一下,可以得到后边这个柿子就是\(\mathrm{C}_{n+m+1}^{m+1}-\mathrm{C}_{n+m-p}^{m+1}\)

然后后面的就可以\(O(1)\)求了,直接递推就行,时间复杂度\(O(n^2)\)

点此查看代码
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,t,p) for(int i = s;i <= t;i += p)
#define drep(i,s,t,p) for(int i = s;i >= t;i -= p)
#ifdef LOCAL
    FILE *InFile = freopen("in.in","r",stdin),*OutFile = freopen("out.out","w",stdout);
#else
    FILE *InFile = freopen("dba.in","r",stdin),*OutFile = freopen("dba.out","w",stdout);
#endif
using ll = long long;using ull = unsigned long long;
using db = double;using ldb = long double;
const int N = 2e3 + 10,mod = 1e9 + 7;
inline int power(int a,int b,int mod){
    int res = 1;
    for(;b;b >>= 1,a = 1ll*a*a%mod)
        if(b&1) res = 1ll*res*a%mod;
    return res;
}
inline int Inv(int a){return power(a,mod-2,mod);}
int fac[N*N],inv[N*N],m,n,a[N],sum[N];
inline int C(int n,int m){return m>n?0:1ll*fac[n]*inv[n-m]%mod*inv[m]%mod;}
inline void solve(){
    cin>>m>>n;rep(i,1,n,1) cin>>a[i],a[i] += a[i - 1];
    fac[0] = 1;rep(i,1,m*n,1) fac[i] = 1ll*fac[i-1]*i%mod;
    inv[m*n] = Inv(fac[m*n]);
    drep(i,m*n-1,0,1) inv[i] = 1ll*inv[i+1]*(i+1)%mod;
    ll ans = 0;
    rep(i,1,n,1){
		int S = a[n] - a[i - 1] ; 
		rep(j,0,n-i,1){
            int sgn = j&1?-1:1;
			ans = ((((1ll*sgn*C(n-i,j)*((1ll*C(S-j*m+n-i,n-i)-C(S-a[i]+a[i-1]-j*m+n-i,n-i)+mod)%mod))%mod)+mod)%mod+ans)%mod; 
		}
	}
    cout<<ans;
}
signed main(){
    cin.tie(nullptr)->sync_with_stdio(false);
    solve();
}

T4

不会
image
image
image

有人说座位是按模拟赛调的,那我以后赛时都不交,看看他能给我排到哪里。

posted @ 2024-11-05 19:22  CuFeO4  阅读(25)  评论(0编辑  收藏  举报