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';
}
}
回滚莫队