首页 > 其他分享 >暑假集训csp提高模拟27

暑假集训csp提高模拟27

时间:2024-08-22 17:53:06浏览次数:10  
标签:27 集训 int long operatorname dfn FILE using csp

赛时 rank 17,T1 100,T2 0,T3 0,T4 70

T2一眼OSU的拓展版,懒得打了。

T4写了一个奇怪的做法,轻轻松松拿70?

T3读假题了,然后间接导致了我与STL和pbds斗智斗勇。

题可能不算很难但是我糖

线性只因

用bitset记录每个数在二进制下的每一位,从高位到低位贪心即可。

如果可以的数小于m个,那么就舍弃这一位。

点此查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
// using namespace __gnu_pbds;
// using namespace __gnu_cxx;
using namespace std;
#define infile(x) freopen(x,"r",stdin)
#define outfile(x) freopen(x,"w",stdout)
#define errfile(x) freopen(x,"w",stderr)
#ifdef LOCAL
    FILE *InFile = infile("in.in"),*OutFile = outfile("out.out");
    // FILE *ErrFile=errfile("err.err");
#else
    FILE *Infile = stdin,*OutFile = stdout;
    //FILE *ErrFile = stderr;
#endif
using ll=long long;using ull=unsigned long long;
using db = double;using ldb = long double;
const int N = 1e6 + 10;
int n,m,a[N];
bitset<N> vis[31];
inline void solve(){
    cin>>n>>m;
    for(int i = 1;i <= n; ++i) cin>>a[i];
    for(int i = 30;i >= 0; --i){
        for(int j = 1;j <= n; ++j)
            if((a[j]>>i)&1) vis[i][j] = true;
    }
    bitset<N> res;res.set();
    int bg = 0;
    for(int i = 30;i >= 0; --i){
        if(vis[i].count() >= m){
            bg = i;
            break;
        }
    }
    res = vis[bg];
    int ans = 0;
    for(int i = bg;i >= 0; --i){
        if((vis[i]&res).count() >= m) ans |= (1<<i),res&=vis[i];
    }
    cout<<ans<<'\n';
}
signed main(){
    cin.tie(nullptr)->sync_with_stdio(false);
    cout.tie(nullptr)->sync_with_stdio(false);
    solve(); 
}

金箱子

OSU拓展版,就是记录\(x^0,x^1,\dots,x^k\)的期望,递推转移

如何记录\(x^k\)的期望?由二项式定理,有\((x+a)^k=\sum_{i=0}^kC_k^ix^ia^{k-i}\)

然后就这么维护就可以了

点此查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
// using namespace __gnu_pbds;
using namespace __gnu_cxx;
using namespace std;
#define infile(x) freopen(x,"r",stdin)
#define outfile(x) freopen(x,"w",stdout)
#define errfile(x) freopen(x,"w",stderr)
#ifdef LOCAL
    FILE *InFile = infile("in.in"),*OutFile = outfile("out.out");
    // FILE *ErrFile=errfile("err.err");
#else
    FILE *Infile = stdin,*OutFile = stdout;
    //FILE *ErrFile = stderr;
#endif
using ll=long long;using ull=unsigned long long;
using db = double;using ldb = long double;
const int N = 1e4 + 10,mod = 998244353;
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;
}
int f[N][110],t[N][110],fac[N],inv[N],n,k;
inline int C(int n,int m){return 1ll * fac[n] * inv[m] % mod * inv[n - m] % mod;}
struct node{int p1,p2,a,b;}a[N];
inline void solve(){
    cin>>n>>k;
    for(int i = 1;i <= n; ++i) cin>>a[i].p1>>a[i].a>>a[i].b,a[i].p2 = 1-a[i].p1+mod;

    fac[0] = 1;
    for(int i = 1;i < N; ++i) fac[i] = 1ll * fac[i - 1] * i % mod;
    inv[N - 1] = power(fac[N - 1],mod - 2,mod);
    for(int i = N - 2;i >= 0; --i) inv[i] = 1ll * inv[i + 1] * (i + 1) % mod;
    
    for(int i = 1;i <= n; ++i)
        for(int j = 0;j <= k; ++j)
            t[i][j] = (1ll*power(a[i].a,j,mod)*a[i].p1%mod+1ll*power(a[i].b,j,mod)*a[i].p2%mod)%mod;
    f[1][0] = 1;
    for(int i = 1;i <= k; ++i) f[1][i] = t[1][i];
    for(int i = 2;i <= n; ++i){
        f[i][0] = 1;
        for(int j = 1;j <= k; ++j){
            for(int k = 0;k <= j; ++k){
                f[i][j] = (f[i][j] + 1ll*C(j,k)*f[i-1][k]%mod*t[i][j-k]%mod)%mod;
            }
        }
    }
    cout<<f[n][k]<<'\n';
}
signed main(){
    cin.tie(nullptr)->sync_with_stdio(false);
    cout.tie(nullptr)->sync_with_stdio(false);
    solve(); 
}

可持久化字符串

考虑到每次只是加减一个字符,那么将一个版本插到一颗\(Trie\)上,对于每次增减,直接在上一个版本的末尾处增减即可。

在\(Trie\)树上每一个节点开一个vector,记录当前位置为那些版本的末尾。

将询问离线下来,记录一下。

在\(Trie\)树上跑AC自动机,然后字符串匹配即可。
复杂度 \(O(n)\)。

注意查询时要用拓扑排序,不然会T

赛后因为早版本的大样例有锅被硬控了2h

点此查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
// using namespace __gnu_pbds;
// using namespace __gnu_cxx;
using namespace std;
#define infile(x) freopen(x,"r",stdin)
#define outfile(x) freopen(x,"w",stdout)
#define errfile(x) freopen(x,"w",stderr)
#ifdef LOCAL
    FILE *InFile = infile("in.in"),*OutFile = outfile("out.out");
    FILE *ErrFile=errfile("err.err");
#else
    FILE *Infile = stdin,*OutFile = stdout;
    //FILE *ErrFile = stderr;
#endif
using ll=long long;using ull=unsigned long long;
using db = double;using ldb = long double;
#define int long long
const int N = 1e5 + 10;
class BIT{
private:
    int tree[N];
#define lowbit(x) (x&(-x))
public:
    int mx = N-10;
    inline void update(int pos,int val){
        pos++;
        for(int i = pos;i <= mx + 3; i += lowbit(i)) tree[i] += val;
    }
    inline int query(int pos){
        int res = 0;
        for(int i = pos; i;i -= lowbit(i)) res += tree[i];
        return res;
    }
}T;
#define get(x) (x-'a'+1)
class Auto_Maton{
private:
    int trie[N][27],fail[N],fa[N],rd[N],cnt[N];
    vector<int> pos[N];
public:
    Auto_Maton(){pos[0].emplace_back(0);}
    int tot;
    inline int insert(int from,int id,char s){
        int x = get(s);
        int p = trie[from][x]?trie[from][x]:trie[from][x] = ++tot;
        fa[p] = from;
        pos[p].emplace_back(id);
        return p;
    }
    inline int erase(int from,int id){pos[fa[from]].emplace_back(id);return fa[from];}
    inline void build(){
        queue<int> q;
        for(int i = 1;i <= 26; ++i) 
            if(trie[0][i]) q.push(trie[0][i]),fail[trie[0][i]] = 0;
        while(q.size()){
            int x = q.front();q.pop();
            for(int i = 1;i <= 26; ++i){
                if(trie[x][i]) 
                    fail[trie[x][i]] = trie[fail[x]][i],q.push(trie[x][i]),++rd[trie[fail[x]][i]];
                else trie[x][i] = trie[fail[x]][i];
            }
        }
    }
    inline void get_ans(string s){
        build();int p = 0;
        for(char x:s) p = trie[p][get(x)],++cnt[p];
        queue<int> q;
        for(int i = 1;i <= tot; ++i) if(!rd[i]) q.push(i);
        while(q.size()){
            int x = q.front();q.pop();
            if(cnt[x]) for(auto k:pos[x]) T.update(k,cnt[x]);
            if(fail[x]){
                cnt[fail[x]] += cnt[x];
                --rd[fail[x]];
                if(!rd[fail[x]]) q.push(fail[x]);
            }
        }
        for(auto k : pos[0]) T.update(k,1);
    }
}AC;
int n,m,pos[N],cnt;
string b;
vector<pair<int,int> > que;
inline void solve(){
    cin>>n>>m>>b;
    char x;
    for(int i = 1,op,p,l,r;i <= n; ++i){
        cin>>op;
        if(op == 1){
            cin>>p>>x;
            ++cnt;
            pos[cnt] = AC.insert(pos[p],cnt,x);
        }
        if(op == 2){
            cin>>p;cnt++;
            pos[cnt] = AC.erase(pos[p],cnt);
        }
        if(op == 3){
            cin>>l>>r;
            que.emplace_back(make_pair(l,r));
        }
    }
    AC.get_ans(b);
    for(auto i:que){
        cout<<T.query(i.second+1)-T.query(i.first)<<'\n';
    }
}
signed main(){
    cin.tie(nullptr)->sync_with_stdio(false);
    cout.tie(nullptr)->sync_with_stdio(false);
    solve(); 
}

圣诞树

写了一个神奇的暴力,就是用bitset记录每一个链的贡献,但是如果树退化成链就会寄,于是就将一条大链再砍成几个小链,暴力跳即可,时间复杂度未知,和\(O(n\sqrt{n})\)的莫队一样都是70pts(都在最后两个点被卡了)

正解是整体二分,不会,贺了

考虑利用每个朋友最多送给 chino 一件礼物这个性质,考虑离线后做整体二分,设当前二分的值为 \(mid\) ,那么我们需要对于每个询问求解树上路径中 \([L,mid]\) 值域中出现的数的种数。

发现所有权值的出现情况只有 \(3\) 种:当前权值只出现 \(1\) 次,当前权值出现 \(2\) 次并且出现的位置具有祖先关系,当前权值出现 \(2\) 次并且出现位置没有祖先关系。

假设所有询问 \((x,y)\) 均满足 \(x\) 的 \(\operatorname{dfn}\) 序小于等于 \(y\) 的 \(\operatorname{dfn}\) 序。

考虑第一种情况会贡献到的询问,设出现的位置为 \(u\) ,容易发现这会贡献到 \(\operatorname{dfn}_x\in [\operatorname{dfn}_u, \operatorname{dfn}_u + \operatorname{size}_u - 1], \operatorname{dfn}_y \in [\operatorname{dfn}_u + \operatorname{size}_u, n]\) 和 \(\operatorname{dfn}_x \in [1, \operatorname{dfn}_u - 1], \operatorname{dfn}_y \in [\operatorname{dfn}_u, \operatorname{dfn}_u + \operatorname{size}_u - 1]\) 的询问,需要特殊处理 \(\operatorname{lca}(x, y) = u\) 的询问。

考虑第二种情况,首先按照第一种情况分别处理 \(u, v\) 两点,发现存在一些询问被贡献了两次,设 \(v\) 在 \(u\) 方向上的儿子为 \(p\) ,那么 \(\operatorname{dfn}_x \in [1, \operatorname{dfn}_p - 1], \operatorname{dfn}_y \in [\operatorname{dfn}_u, \operatorname{dfn}_u + \operatorname{size}_u - 1]\) 和 \(\operatorname{dfn}_x \in [\operatorname{dfn}_u, \operatorname{dfn}_u + \operatorname{size}_u - 1], \operatorname{dfn}_y \in [\operatorname{dfn}_p + \operatorname{size}_p, n]\) 的询问会被贡献两次。

考虑第三种情况,仍然按照第一种情况分别处理 \(u,v\) 两端,发现 \(\operatorname{dfn}_x \in [\operatorname{dfn}_u, \operatorname{dfn}_u + \operatorname{size}_u - 1], \operatorname{dfn}_y \in [\operatorname{dfn}_v, \operatorname{dfn}_v + \operatorname{size}_v - 1]\) 的询问会被贡献两次。

于是原问题转化为二维平面上做矩形加,单点查询,可以用扫描线解决,复杂度为 \(O(n\log^2n)\) ,使用树状数组后可以在 \(1200ms\) 通过本题。

标签:27,集训,int,long,operatorname,dfn,FILE,using,csp
From: https://www.cnblogs.com/hzoi-Cu/p/18374442

相关文章

  • 『模拟赛』暑假集训CSP提高模拟27 || The End
    《$Never\;Over$》好久没推歌了。Idon'tknowwhattosayIdon'tknowwhattodoIjustwannagorightbacktoyouLikeacloudintheskyMytearsfallforyouIwouldpaintmylifeWhitejusttomakeyoublueCausebabyyouknowweshouldbetogethe......
  • csp模拟27-金箱子(题解)
    题目链接(显然还没有找到原题)虽说我现在才学会期望dp显得不太好,但没办法,谁让我比较菜~~,之前模拟赛已经考过几道类似的题了,但都一笔带过了,这次算是正式学习了一下这类题,于是就有了这篇题解。首先看到k次方首先想到的就是我们在进行dp转移的时候不太方便,这个时候很自然的想到二项......
  • 暑假集训CSP提高模拟27
    暑假集训CSP提高模拟27组题人:@KafuuChinocpp\(T1\)P236.线性只因\(100pts\)诈骗题。部分分正解记\(opt\)表示待选集合,统计\(opt\)中这一位为\(1\)的数并加入临时集合\(tmp\)。若\(tmp\)大小\(\gem\)则加上这一位的贡献并将\(opt\)赋成\(tmp\)......
  • CSP防爆
    今日模拟赛T3把ac.inac.out愣是写成ac.txtac.txt自己在IDE里测大样例用的是.txt,提交没改过来100->0啊啊啊啊啊啊啊啊啊啊啊啊T6见祖宗0<=x<=1e9还要求和爆int但我没看见.....(100->90啊啊啊啊啊啊啊啊啊啊啊啊430->340经验考试绝不开多个页面,容易看错内存不紧......
  • 集训总结
    前言:写于2024年暑假中山集训期间,如果有误,望指出。20240729D1感觉今天整体还行,T1一眼题。T2胡了一个dp,死在没考虑到优化状态。T3裴蜀定理(忘了),T4建模Johnson。dp有点死板,可以考虑从不同的角度设计dp状态,比如交换dp的维度和其维护的值。数论还是需要巩固,竟然连裴蜀定理都......
  • 2024暑期第二次集训总结(202408)
    坐标cssyz08.12身体不适,请假在家,随便写写,把当天任务写了一下,结果你谷RMJ炸了,直接躺平。08.13上午原定9:00-12:00出去比赛,让我们8:00到,到了之后又没事做,直接与同学联机MC,后面开考,以为是csp-j难度,结果红+红+下位橙+红,14分钟秒了。(抽象)回到机房赶上思维训练,看了......
  • YC327A [ 20240821 CQYC NOIP 模拟赛 T1 ] 最值(minmax)
    题意对于一个序列\({b_n}\),规定:\[f_min(b)=\prod_{i=1}^n(min_{j=1}^ib_j)\]\[f_max(b)=\prod_{i=1}^n(max_{j=1}^ib_j)\]给定一个序列\(a\),求\(a\)所有的排列\(p\)的\(f_min(p)\)与\(f_max(p)\)之和。\(n\le5000\)Sol不难想到一个简......
  • 2024.8.21 总结(集训 考试)
    上午感觉不错,下午改不出题,晚上破防。简略思路:T1本质应该是DP维护一次函数。不会正解。晚上看了好久、好多篇题解还是不会。有点静不下心来看比较长的题解。放点别人的题解,有空再来研究:https://www.cnblogs.com/flywatre/p/17236732.htmlhttps://blog.51cto.com/u_1530083......
  • 『模拟赛』暑假集训CSP提高模拟26
    Rank打得一般,倒数第二场了。。A.博弈直接搬了牛客的一套题。一眼没思路,模了一会放弃直接去打T2了,后来把\(\mathcal{O(n^2)}\)暴力打了拿30pts。正解用到了异或哈希。首先确定合法的数量即为总对数\(\frac{n(n-1)}{2}\)减去不合法的数量,而比较显然的,不合法的判断......
  • [赛记] 暑假集训CSP提高模拟24
    与和100pts签到题但还是做了很久。。。考虑与的条件,可以发现,如果将$a$转化成二进制,那么二进制上为$1$的位置$x$和$y$都必须是$1$,所以首先将$s$减去$2\timesa$,然后再判断一下$(s-2\timesa)\operatorname{and}a$是否为$0$即可;赛时用......