5月3日模拟赛题解(李时珍的皮肤衣 , 马大嘴的废话 , SSY的队列 , 清理牛棚 , 历史の研究)

T1 李时珍的皮肤衣

发现是二进制进位,所以直接快速幂即可。

#include<bits/stdc++.h>
#define int __int128
inline int read(){
    char ch=getchar();int x=0,f=1;
    for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
    return x*f;
}
const int N=1e6;
int f[N],n;
inline int qpow(int a,int b){
    int ans=1;
    for(;b;b>>=1,a=a*a%n)if(b&1)ans=ans*a%n;
    return ans;
}
signed main(){
    freopen("lsz.in","r",stdin),freopen("lsz.out","w",stdout);
    std::ios::sync_with_stdio(false);
    std::cin.tie(0),std::cout.tie(0);
    n=read();
    std::cout<<(long long)((qpow(2,n-1)+1)%n);
}

T2 马大嘴的废话

数据范围小,暴力做或者trie树都可以,卡了单模数哈希,加强版本是P2336 [SCOI2012] 喵星球上的点名 (AC自动机)
hash

#include<bits/stdc++.h>
#define int long long
inline int read(){
    char ch=getchar();int x=0,f=1;
    for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
    return x*f;
}
const int N=1e5+10,P=233,mod=1e9+93,mod1=1e9+97;
std::map<std::pair<int,int>,int> mp,un;
int n,m,hs[25],_p[30],_p1[30],hsa[25];
char s[25];
signed main(){
    freopen("mdz.in","r",stdin),freopen("mdz.out","w",stdout);
    std::ios::sync_with_stdio(false);
    std::cin.tie(0),std::cout.tie(0);
    std::cin>>n;
    _p[0]=1;_p1[0]=1;
    for(int i=1;i<=25;++i)_p[i]=_p[i-1]*P%mod,_p1[i]=_p1[i-1]*P%mod1;
    for(int i=1;i<=n;++i){
        std::cin>>s+1;
        // std::cout<<s+1<<'\n';
        int len=strlen(s+1);
        for(int j=1;j<=len;++j){
            hs[j]=(hs[j-1]*P%mod+s[j])%mod;
            hsa[j]=(hsa[j-1]*P%mod1+s[j])%mod1;
        }
        for(int r=1;r<=len;++r){
            for(int l=1;l<=r;++l){
                int zc=((hs[r]-hs[l-1]*_p[r-l+1]%mod)%mod+mod)%mod;
                int zc1=((hsa[r]-hsa[l-1]*_p1[r-l+1]%mod1)%mod1+mod1)%mod1;
                if(!un[{zc,zc1}])mp[{zc,zc1}]++,un[{zc,zc1}]=1;
            }
        }
        un.clear();
    }
    std::cin>>m;
    for(int i=1;i<=m;++i){
        std::cin>>s+1;
        int len=strlen(s+1);
        int zc=0,zc1=0;
        for(int j=1;j<=len;++j){
            zc=(zc*P%mod+s[j])%mod;
            zc1=(zc1*P%mod1+s[j])%mod1;
        }
        std::cout<<mp[{zc,zc1}]<<'\n';
    }
}

T3 ssy的队列

有意思的题,学到一个trick,拿哈希划分数来表示状态,然后直接转移即可。
先将序列中的数按模数分类,统计各类数有多少个。
\(f_{i,j,v}\) 表示序列排到第 \(i\) 位,最后选的一类数还剩 \(j\) 个,所有类数剩的个数状态为 \(v\) 时的方案数。
因为我们只关注状态的情况,所以第三维状态与顺序无关,这样大大减少了状态数。第三维的总状态只有 \(n\) 的划分数那样多。关于划分数相关知识
然后直接开始枚举,遍历 map,刷表即可。
当n比较大时怎么做?

#include<bits/stdc++.h>
typedef unsigned long long ull;
#define int long long
inline int read(){
    char ch=getchar();int x=0,f=1;
    for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
    return x*f;
}
const int N=35,mod=1234567891;
int n,m,a[N],tot,num[N],jc[N];
std::unordered_map<int,int> t;
std::map<std::vector<int>,int> f[N][N];
signed main(){
    freopen("ssy.in","r",stdin);freopen("ssy.out","w",stdout);
    n=read();
    for(int i=1;i<=n;++i)a[i]=read();
    m=read();
    for(int i=1;i<=n;++i){
        a[i]%=m;a[i]=(a[i]+m)%m;
        if(!t[a[i]])t[a[i]]=++tot;
        a[i]=t[a[i]];num[a[i]]++;
    }
    std::vector<int> v;
    for(int i=1;i<=tot;++i)v.push_back(num[i]);
    std::stable_sort(v.begin(),v.end());f[0][0][v]=1;
    for(int i=0;i<n;++i)
        for(int j=0;j<=n;++j)
            for(auto it=f[i][j].begin();it!=f[i][j].end();++it){
                v=it->first;bool vis=0;
                for(int pos=0;pos<v.size();++pos){
                    int x=v[pos];
                    if(!x)continue;
                    if(x==j&&!vis){vis=true;continue;}
                    std::vector<int> zc=v;
                    zc[pos]--;
                    std::stable_sort(zc.begin(),zc.end());
                    f[i+1][x-1][zc]=(f[i+1][x-1][zc]+it->second)%mod;
                }
            }
    jc[0]=1;for(int i=1;i<=n;++i)jc[i]=jc[i-1]*i%mod;
    int ans=1;for(int i=1;i<=tot;++i)ans=ans*jc[num[i]]%mod;
    v.clear();for(int i=1;i<=tot;++i)v.push_back(0);
    std::cout<<ans*f[n][0][v]%mod<<'\n';
}

T4 清理牛棚

一眼可以看出是一个数据结构优化DP之类的东西(也有最短路的巧妙做法)。赛时写了假做法,过了,所以开始口胡
\(f_i\) 表示到 \(i\) 时间的最小花费,显然有 \(f_{r_i}=\min(f_{r_k})+s_i(l_i-1\le r_k)\),将牛的相关信息排序后直接拿线段树区间修改查询即可。(代码不贴了)

T5 歴史の研究

出板子题没意思,写的分块,回滚莫队当时直接跳了,等会补。和蒲公英一样。

分块
#include<bits/stdc++.h>
#define int long long
inline int read(){
    char ch=getchar();int x=0,f=1;
    for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
    return x*f;
}
const int N=1e5+10,LEN=350;
int n,Q,t[LEN][N],len,id[N],temp[N],a[N],mp[N],s[LEN][LEN];
struct BLOCK{int l,r;}blo[LEN];
inline int ask(int l,int r){
    if(id[r]-id[l]<=1){
        int ret=0;
        for(int i=l;i<=r;++i){
            mp[a[i]]++;
            ret=std::max(ret,mp[a[i]]*temp[a[i]]);
        }
        for(int i=l;i<=r;++i)mp[a[i]]=0;
        return ret;
    }
    else{
        int ans=s[id[l]+1][id[r]-1];
        for(int i=l;id[i]==id[l];++i){
            mp[a[i]]++;
            int cnt=t[id[r]-1][a[i]]-t[id[l]][a[i]];
            ans=std::max(ans,(mp[a[i]]+cnt)*temp[a[i]]);
        }
        for(int i=r;id[i]==id[r];--i){
            mp[a[i]]++;
            int cnt=t[id[r]-1][a[i]]-t[id[l]][a[i]];
            ans=std::max(ans,(mp[a[i]]+cnt)*temp[a[i]]);
        }
        for(int i=l;id[i]==id[l];++i)mp[a[i]]=0;
        for(int i=r;id[i]==id[r];--i)mp[a[i]]=0;
        return ans;
    }
}
signed main(){
    // freopen("a.in","r",stdin),freopen("a.out","w",stdout);
    std::ios::sync_with_stdio(false);
    std::cin.tie(0),std::cout.tie(0);
    n=read();len=std::sqrt(n);Q=read();
    for(int i=1;i<=n;++i){
        id[i]=(i-1)/len+1;
        if(id[i]!=id[i-1])blo[id[i]].l=i;
        blo[id[i]].r=i;
        temp[i]=a[i]=read();
    }
    std::stable_sort(temp+1,temp+n+1);
    int _len=std::unique(temp+1,temp+n+1)-temp-1;
    for(int i=1;i<=n;++i)a[i]=std::lower_bound(temp+1,temp+_len+1,a[i])-temp;
    for(int k=1;k<=id[n];++k){
        for(int i=1;i<=_len;++i)t[k][i]=t[k-1][i];
        for(int i=blo[k].l;i<=blo[k].r;++i)t[k][a[i]]++;
    }
    for(int i=1;i<=id[n];++i){
        for(int j=i;j<=id[n];++j){
            int max=s[i][j-1];
            for(int k=blo[j].l;k<=blo[j].r;++k){
                int cnt=t[j][a[k]]-t[i-1][a[k]];
                max=std::max(max,cnt*temp[a[k]]);
            }
            s[i][j]=max;
        }
    }
    for(int i=1;i<=Q;++i){
        int l=read(),r=read();
        std::cout<<ask(l,r)<<'\n';
    }
}
回滚莫队
#include<bits/stdc++.h>
#define int long long
inline int read(){
	char ch=getchar();int x=0,f=1;
	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
	return x*f;
}
const int N=1e5+10;
int n,Q,a[N],temp[N],ANS[N],len,last,id[N],t[N],t1[N];
struct QUE{int l,r,id;}q[N],blo[N];
inline bool cmp(QUE a,QUE b){if(id[a.l]==id[b.l])return a.r<=b.r;return id[a.l]<id[b.l];}
signed main(){
	// freopen("in.in","r",stdin),freopen("out.out","w",stdout);
	std::ios::sync_with_stdio(false);std::cin.tie(0),std::cout.tie(0);
	n=read();Q=read();len=std::sqrt(n);
	for(int i=1;i<=n;++i){
		temp[i]=a[i]=read();
		id[i]=(i-1)/len+1;
		if(id[i]!=id[i-1])blo[id[i]].l=i;
		blo[id[i]].r=i;
	}
	std::stable_sort(temp+1,temp+1+n);int _len=std::unique(temp+1,temp+1+n)-temp-1;
	for(int i=1;i<=n;++i)a[i]=std::lower_bound(temp+1,temp+1+_len,a[i])-temp;
	for(int i=1;i<=Q;++i)q[i].l=read(),q[i].r=read(),q[i].id=i;
	std::stable_sort(q,q+Q+1,cmp);
	// for(int i=1;i<=n;++i)std::cout<<a[i]<<' ';std::cout<<'\n';
	int l=0,r=-1,ans=0;
	for(int i=1;i<=Q;++i){
		if(id[q[i].l]==id[q[i].r]){
			ans=0;
			for(int j=l;j<=r;++j)t[a[j]]=0;
			for(int j=q[i].l;j<=q[i].r;++j){ans=std::max(ans,t[a[j]]+=temp[a[j]]);}
			for(int j=q[i].l;j<=q[i].r;++j){t[a[j]]=0;}
			ANS[q[i].id]=ans;ans=0;
		}else{
			if(last!=id[q[i].l]){
				ans=0;
				for(int j=l;j<=r;++j)t[a[j]]=t1[a[j]]=0;
				last=id[q[i].l];
				l=blo[last+1].l;r=blo[last].r;
			}
			while(r<q[i].r)r++,ans=std::max(ans,t[a[r]]+=temp[a[r]]);
			int zc=ans;
			while(l>q[i].l)--l,t1[a[l]]+=temp[a[l]],zc=std::max(zc,t1[a[l]]+t[a[l]]);
			while(l<blo[last].r+1)t1[a[l]]=0,l++;
			ANS[q[i].id]=zc;
		}
	}
	for(int i=1;i<=Q;++i)std::cout<<ANS[i]<<'\n';
}
posted @ 2024-05-04 16:08  Ishar-zdl  阅读(62)  评论(0)    收藏  举报