多校A层冲刺NOIP2024模拟赛24

选取字符串

建出失配树以后直接dp就好了。但场上现推的kmp……

点此查看代码
#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("string.in","r",stdin),*OutFile = freopen("string.out","w",stdout);
    // FILE *InFile = stdin,*OutFile = stdout;
#endif
using ll=long long;using ull=unsigned long long;
using db = double;using ldb = long double;
#define int long long
const int N = 1e6 + 10,mod = 998244353;
int n,k,fac[N<<2],inv[N<<2],sum[N],nxt[N],ct[N],dep[N],siz[N],ans = 0;
char s[N];
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);}
inline int C(int n,int m){
    if(m > n) return 0;
    return 1ll*fac[n]*inv[m]%mod*inv[n-m]%mod;
}
vector<int> son[N];
void dfs(int x){
    dep[x] = dep[nxt[x]] + 1;
    siz[x] = 1;
    for(auto y:son[x]){
        dfs(y);
        siz[x] += siz[y];
        ct[x] = (ct[x] - C(siz[y],k) + mod)%mod;
    }
    ct[x] = (ct[x] + C(siz[x],k))%mod;
    ans = (ans + 1ll*ct[x]*dep[x]%mod*dep[x]%mod)%mod;
}
inline void solve(){
    cin>>k>>(s+1);n = strlen(s+1);
    n<<=2;
    fac[0] = 1;rep(i,1,n,1) fac[i] = 1ll*fac[i-1]*i%mod;
    inv[n] = Inv(fac[n]);drep(i,n-1,0,1) inv[i] = 1ll*inv[i+1]*(i+1)%mod;
    n>>=2;
    int j = 0;
    son[0].emplace_back(1);
    rep(i,2,n,1){
        while(j && s[i] != s[j+1]) j = nxt[j];
        j += (s[i] == s[j+1]);
        nxt[i] = j;son[nxt[i]].emplace_back(i);
    }
    dfs(0);
    cout<<ans;
}
signed main(){
    cin.tie(nullptr)->sync_with_stdio(false);
    solve();
}

取石子

打表找规律发现当且仅当\(lowbit(\oplus_ia_i)\le k\)时先手必胜。

然后发现每次增加的一定为\(2^k\)且不降,直接暴力枚举即可,时间复杂度\(O(n\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);
#else
    // FILE *InFile = stdin,*OutFile = stdout;
    FILE *InFile = freopen("nim.in","r",stdin),*OutFile = freopen("nim.out","w",stdout);
#endif
using ll=long long;using ull=unsigned long long;
using db = double;using ldb = long double;
#define int long long
const int N = 5e4 + 10;
int n,k,a[N];
bool f[50],flag,cp[50];
inline void solve(){
    cin>>n>>k;rep(i,1,n,1) cin>>a[i];
    int lgk = __lg(k);
    rep(i,0,lgk,1){rep(j,1,n,1) f[i]^=(a[j]>>i)&1;flag |= f[i];}
    if(!flag) cout<<"0\n";
    else{
        cout<<"1\n";
        rep(i,1,n,1){
            rep(j,0,lgk,1) cp[j] = f[j];
            int sum = 0;
            rep(j,0,__lg(a[i]),1){
                if(!cp[j]) continue;
                sum |= 1<<j;
                if(sum > k) break;
                cout<<i<<' '<<sum<<'\n';
                rep(l,j,lgk,1) cp[l] ^= a[i]>>l&1;
                a[i] -= 1<<j;
                rep(l,j,lgk,1) cp[l] ^= a[i]>>l&1;
            }
        }
    }
}
signed main(){cin.tie(nullptr)->sync_with_stdio(false);solve();}

均衡区间

\(ml_{i},sl_{i},mr_{i},sr_{i}\)分别表示左边第一个比\(a_i\)大的数的位置,左边第一个比\(a_i\)小的数的位置,右边第一个比\(a_i\)大的数的位置,右边第一个比\(a_i\)小的数的位置。记\(L_{i}=\min\{ml_{i},sl_{i}\}\)

假如\([i,j]\)是一个合法区间,那么有\(i<L_{j}\And R_{i}<j\),二维数点。正反求两遍就好了。

点此查看代码
#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 = stdin,*OutFile = stdout;
    FILE *InFile = freopen("interval.in","r",stdin),*OutFile = freopen("interval.out","w",stdout);
#endif
using ll=long long;using ull=unsigned long long;
using db = double;using ldb = long double;
const int N = 1e6 + 10;
int n,a[N],ans1[N],ans2[N],id;
int mr[N],ml[N],sr[N],sl[N],L[N],R[N];
struct BIT{
    int mx,tree[N];
    inline void init(int n){mx = n;memset(tree,0,sizeof tree);}
    inline int lb(int x){return (x&(-x));}
    inline void upd(int pos,int val){rep(i,pos,mx,lb(i)) tree[i] += val;}
    inline int qry(int pos){int res = 0;drep(i,pos,1,lb(i)) res += tree[i];return res;}
}T;
stack<int> sta;
inline void get(int *ans){
    drep(i,n,1,1){while(sta.size() && a[sta.top()] < a[i]) ml[sta.top()] = i,sta.pop();sta.push(i);}
    while(sta.size()) ml[sta.top()] = 1,sta.pop();
    drep(i,n,1,1){while(sta.size() && a[sta.top()] > a[i]) sl[sta.top()] = i,sta.pop();sta.push(i);}
    while(sta.size()) sl[sta.top()] = 1,sta.pop();
    rep(i,1,n,1){while(sta.size() && a[sta.top()] < a[i]) mr[sta.top()] = i,sta.pop();sta.push(i);}
    while(sta.size()) mr[sta.top()] = n,sta.pop();
    rep(i,1,n,1){while(sta.size() && a[sta.top()] > a[i]) sr[sta.top()] = i,sta.pop();sta.push(i);}
    while(sta.size()) sr[sta.top()] = n,sta.pop();
    rep(i,1,n,1) L[i] = min(ml[i],sl[i]),R[i] = max(mr[i],sr[i]);
    T.init(n);vector<pair<int,int> > vec;
    rep(i,1,n,1) vec.emplace_back(L[i],i);
    sort(vec.begin(),vec.end(),greater<pair<int,int> >());
    int now = -1;
    drep(i,n,1,1){
        while(now < n-1 && vec[now+1].first > i){now++;T.upd(vec[now].second,1);}
        ans[i] = T.qry(T.mx)-T.qry(R[i]);
    }
}
inline void solve(){
    cin>>n>>id;rep(i,1,n,1) cin>>a[i];
    get(ans1);
    rep(i,1,n,1) cout<<ans1[i]<<' ';cout<<'\n';
    reverse(a+1,a+1+n);get(ans2);
    reverse(ans2+1,ans2+1+n);
    rep(i,1,n,1) cout<<ans2[i]<<' ';
}
signed main(){cin.tie(nullptr)->sync_with_stdio(false);solve();}

禁止套娃

不会。

p

image

posted @ 2024-11-19 21:20  CuFeO4  阅读(25)  评论(1编辑  收藏  举报