A层邀请赛3

日常垫底,赛个球

A. 玩个球

组合数DP,搞了个傻逼性质在那乱转移,结果还是只有n==2的分,有趣的是中间交的一份码过了n==3的,但是不是最后一次提交。。

正解

dp[i][j]表示放了i个白球,有j个颜色放完的方案数,主要思想在枚举剩余位置的第一个放啥

考虑放白球,直接转移

放颜色,先选一个颜色,此时剩下 k2 个,再用组合数求k2个数放在后面的方案数

code
#include<cstdio>
#include<cstring>

using namespace std;
typedef long long ll;
const int maxn = 2005;
const int mod = 1e9 + 7;
int fac[maxn * maxn], inv[maxn * maxn];
int qpow(int x, int y){
    int ans = 1;
    for(; y; y >>= 1, x = 1ll * x * x % mod)if(y & 1)ans = 1ll * ans * x % mod;
    return ans;
}
void pre(int mx){
    fac[0] = 1; for(int i = 1; i <= mx; ++i)fac[i] = 1ll * fac[i - 1] * i % mod;
    inv[mx] = qpow(fac[mx], mod - 2); for(int i = mx - 1; i; --i)inv[i] = 1ll * inv[i + 1] * (i + 1) % mod;
    inv[0] = 1;
}
int C(int n, int m){return 1ll * fac[n] * inv[m]  % mod * inv[n - m] % mod;}
int n, k, f[maxn][maxn]; 
int main(){
    scanf("%d%d", &n, &k);
    pre(n * k);
    for(int i = 1; i <= n; ++i){
        f[i][0] = 1;
        for(int j = 1; j <= i; ++j){
            f[i][j] = (f[i - 1][j] + 1ll * f[i][j - 1] * (n - j + 1) % mod * C(n * k - (j - 1) * (k - 1) - i - 1, k - 2) % mod) % mod; 
        }
    }
    printf("%d\n",f[n][n] % mod);
    return 0;
}

B. 序列

刚讲过类似的常规套路就忘了。。。。

线段树维护ir的值,记录上一个与当前值相同的数的位置, 然后就是类似HH的项链的区间修改,查询最小值,为0boring

另一种思路,每次找到区间中只出现一次的数,然后拆分问题为该数左右两边的区间

暴力找复杂度不对,考虑启发式,从两边同时向里找,这样复杂度就是nlogn级别了

code
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;
const int maxn = 200055;
inline int read(){
    int x = 0; char c = getchar();
    while(c < '0' || c > '9')c = getchar();
    do{x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}while(c >='0' && c <= '9');
    return x;
}
int n, a[maxn], b[maxn], pre[maxn], nxt[maxn], rm[maxn];
bool solve(int l, int r){
    if(l >= r)return true;
    int len = r - l + 1;
    int mx = (len + 1) >> 1;
    int pos = -1;
    for(int i = 1; i <= mx; ++i){
        int nl = l + i - 1, nr = r - i + 1;
        if(pre[nl] < l && nxt[nl] > r){pos = nl;break;}
        if(pre[nr] < l && nxt[nr] > r){pos = nr;break;}
    }
    if(pos == -1)return false;
    return solve(l, pos - 1) && solve(pos + 1, r)
}
inline bool work(){
    n = read();
    for(int i = 1; i <= n; ++i)a[i] = read();
    for(int i = 1; i <= n; ++i)b[i] = a[i];
    sort(b + 1, b + n + 1);
    for(int i = 1; i <= n; ++i)a[i] = lower_bound(b + 1, b + n + 1, a[i]) - b;
    for(int i = 1; i <= n; ++i)pre[i] = 0;
    for(int i = 1; i <= n; ++i)nxt[i] = 0;
    for(int i = 1; i <= n; ++i)rm[i] = 0;
    for(int i = 1; i <= n; ++i){
        pre[i] = rm[a[i]];
        nxt[rm[a[i]]] = i;
        rm[a[i]] = i;
    }
    for(int i = 1; i <= n; ++i)nxt[rm[a[i]]] = n + 1;
    return solve(1, n);
}
int main(){
    int T = read();
    for(int i = 1; i <= T; ++i)if(work())printf("non-boring\n");else printf("boring\n");
    return 0;
}
posted @   Chen_jr  阅读(46)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示