CSP-S模拟7
由于昨天难了所以就丢了四个套路题上来呗
T1 序列问题
三维偏序类的转移,其中两位偏序时第三维一定偏序,于是可以变成一个log
点击查看代码
#include <bits/stdc++.h>
typedef long long ll;typedef unsigned long long ull; typedef double db;typedef long double ldb;
#define fre(x) freopen(#x ".in","r",stdin),freopen(#x ".out","w",stdout)
#define Rep(i,a,b) for(int i=a;i<=b;++i)
#define Dwn(i,a,b) for(int i=a;i>=b;--i)
#define pii pair<int,int>
#define mair make_pair
#define fir first
#define sec second
using namespace std;
const int maxn=5e5+10,INF=1e9+20051107;
int f[maxn];
int n,a[maxn],b[maxn];
int id[maxn];
bool cmp(const int &x,const int &y){if(b[x]==b[y])return a[x]<a[y];else return b[x]<b[y];}
struct BIT{
#define lowbit(x) (x&-x)
int c[maxn];
void Add(int x,int d){++x;for(;x<=n+1;x+=lowbit(x))c[x]=max(c[x],d);}
int Query(int x){++x;int res=0;for(;x;x-=lowbit(x))res=max(res,c[x]);return res;}
}T;
void solve(){
fre(sequence);
cin>>n;
Rep(i,1,n)cin>>a[i],id[i]=i;
Rep(i,1,n)b[i]=i-a[i];
int len=0;f[0]=0;
sort(id+1,id+n+1,cmp);
Rep(t,1,n){
int i=id[t];
if(a[i]<=i){
f[i]=T.Query(a[i]-1)+1;
T.Add(a[i],f[i]);
}
}
Rep(i,1,n)len=max(len,f[i]);
cout<<len<<"\n";
}
int main (){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);return solve(),0; }
T2 钱仓
套路断环成链,由于 \(x^2+y^2 \leq (x+y)^2\) ,所以移动路线一定不发生包含,选择一个起点,维护冗余的队列,每次贪心从队首取就行。
点击查看代码
#include <bits/stdc++.h>
typedef long long ll;typedef unsigned long long ull; typedef double db;typedef long double ldb;
#define fre(x) freopen(#x ".in","r",stdin),freopen(#x ".out","w",stdout)
#define Rep(i,a,b) for(int i=a;i<=b;++i)
#define Dwn(i,a,b) for(int i=a;i>=b;--i)
#define pii pair<int,int>
#define mair make_pair
#define fir first
#define sec second
#define int ll
using namespace std;
const int maxn=2e5+10,INF=1e17;
int n,a[maxn];
int ans,nxt;
pii tmp[maxn];
int tl,tr;
bool Sol(int l,int r){
int tl=1,tr=0;ans=0;
Rep(i,l,r){
if(a[i]>0)tmp[++tr]=mair(a[i],i);
while(tl<=tr && tmp[tl].fir==0)++tl;
if(tl<=tr && tmp[tl].fir>0)ans+=(i-tmp[tl].sec)*(i-tmp[tl].sec),--tmp[tl].fir;
else return nxt=i,false;
}
return true;
}
void solve(){fre(barn);
cin>>n;
Rep(i,1,n)cin>>a[i],a[i+n]=a[i];
Rep(i,1,n+1){
if(a[i] && a[i-1]==0){
if(Sol(i,i+n-1))return cout<<ans<<"\n",void();
else i=nxt;
}
}
}
#undef int
int main (){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);return solve(),0; }
T3 自然数
发现加数可能并不是很好做,于是可以搞删数,考虑套路线段树,叶子节点i表示当前左界到i的mex,每次把左界删掉,那么从它到它下一次出现之前的位置,mex都一定不大于它,区间覆盖取min即可,无脑吉司机也行,但是由于mex有单调性,所以直接在线段树上二分覆盖就行
点击查看代码
#include <bits/stdc++.h>
typedef long long ll;typedef unsigned long long ull; typedef double db;typedef long double ldb;
#define fre(x) freopen(#x ".in","r",stdin),freopen(#x ".out","w",stdout)
#define Rep(i,a,b) for(int i=a;i<=b;++i)
#define Dwn(i,a,b) for(int i=a;i>=b;--i)
#define pii pair<int,int>
#define mair make_pair
#define fir first
#define sec second
using namespace std;
const int maxn=2e5+10;
int n,a[maxn],mex[maxn];
ll ans;
struct MEX{
int vec[maxn],mex;
void Add(int x){++vec[x];while(vec[mex])++mex;}
}E;
struct Seg{
struct Tree{int mini,lazy;ll sum;}tr[maxn<<2];
void Pushup(int rt){
tr[rt].mini=min(tr[rt<<1].mini,tr[rt<<1|1].mini),
tr[rt].sum=tr[rt<<1].sum+tr[rt<<1|1].sum;
}
void Build(int rt,int l,int r){
tr[rt].lazy=-1;
if(l==r)return tr[rt].mini=tr[rt].sum=mex[l],void();
int mid=(l+r)>>1;
Build(rt<<1,l,mid),Build(rt<<1|1,mid+1,r);
Pushup(rt);
}
void Update(int rt,int l,int r,int w){
tr[rt].mini=tr[rt].lazy=w;
tr[rt].sum=1LL*(r-l+1)*w;
}
void Pushdown(int rt,int l,int r){
if(tr[rt].lazy==-1)return;
int mid=(l+r)>>1;
Update(rt<<1,l,mid,tr[rt].lazy);
Update(rt<<1|1,mid+1,r,tr[rt].lazy);
tr[rt].lazy=-1;
}
void Modify(int rt,int l,int r,int s,int t,int w){
if(l==r)return tr[rt].sum=tr[rt].mini=min(tr[rt].mini,w),void();
int mid=(l+r)>>1;
Pushdown(rt,l,r);
if(s<=l && t>=r){
if(tr[rt<<1|1].mini>=w)Update(rt<<1|1,mid+1,r,w),Modify(rt<<1,l,mid,s,t,w);
else Modify(rt<<1|1,mid+1,r,s,t,w);
return Pushup(rt);
}
if(s<=mid)Modify(rt<<1,l,mid,s,t,w);
if(t>mid)Modify(rt<<1|1,mid+1,r,s,t,w);
Pushup(rt);
}
ll Query(int rt,int l,int r,int s,int t){
if(s<=l && t>=r)return tr[rt].sum;
int mid=(l+r)>>1;ll res=0;
Pushdown(rt,l,r);
if(s<=mid)res+=Query(rt<<1,l,mid,s,t);
if(t>mid)res+=Query(rt<<1|1,mid+1,r,s,t);
return res;
}
}T;
int nxt[maxn],last[maxn];
void solve(){fre(mex);
cin>>n;
Rep(i,1,n)cin>>a[i];
Rep(i,1,n){ if(a[i]<=n)E.Add(a[i]); mex[i]=E.mex;last[i]=n+1; }
last[0]=n+1;
Dwn(i,n,1){
if(a[i]<=n){
nxt[i]=last[a[i]];
last[a[i]]=i;
}
}
T.Build(1,1,n);
Rep(i,1,n){
ans+=T.Query(1,1,n,i,n);
if(a[i]<=n) T.Modify(1,1,n,i+1,nxt[i]-1,a[i]);
}
cout<<ans<<"\n";
}
int main (){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);return solve(),0; }
T4 环路
甚至我之前做过原题,但是由于根本没有把柿子写出来,没反应过来,一种分治套路
点击查看代码
#include <bits/stdc++.h>
typedef long long ll;typedef unsigned long long ull; typedef double db;typedef long double ldb;
#define fre(x) freopen(#x ".in","r",stdin),freopen(#x ".out","w",stdout)
#define Rep(i,a,b) for(int i=a;i<=b;++i)
#define Dwn(i,a,b) for(int i=a;i>=b;--i)
#define pii pair<int,int>
#define mair make_pair
#define fir first
#define sec second
using namespace std;
const int maxn=1e2+10,maxM=1e6+10;
int Mod,n,K;
ll ans;
int prime[maxM],cnt;
int vis[maxM];
struct Matrix{
int a[maxn][maxn];
Matrix(){memset(a,0,sizeof(a));}
void Clear(){memset(a,0,sizeof(a));}
void Init(){Rep(i,1,n)a[i][i]=1;}
friend Matrix operator * (const Matrix &x,const Matrix &y){
Matrix z;
Rep(i,1,n)Rep(k,1,n)
{ int r=x.a[i][k]; Rep(j,1,n)z.a[i][j]=(z.a[i][j]+1LL*r*y.a[k][j])%Mod; }
return z;
}
Matrix Pow(int p){
Matrix res,base=(*this);res.Init();
while(p){if(p&1)res=res*base;p>>=1;base=base*base;}
return res;
}
friend Matrix operator + (const Matrix &x,const Matrix &y){
Matrix z;
Rep(i,1,n)Rep(j,1,n)z.a[i][j]=(x.a[i][j]+y.a[i][j])%Mod;
return z;
}
void operator += (const Matrix &x){ Rep(i,1,n)Rep(j,1,n)a[i][j]=(a[i][j]+x.a[i][j])%Mod; }
void Print(){Rep(i,1,n){ Rep(j,1,n)cerr<<a[i][j]%Mod<<" ";cerr<<"\n";}cerr<<"\n"; }
void Calc(){ Rep(i,1,n)ans+=a[i][i];ans%=Mod; }
}F,G;
char s[maxn];
Matrix Calc(int x){
if(x==1)return F;
int mid=x>>1;
Matrix res=Calc(mid),base=F.Pow(mid);
if(x&1)return (res+(res*base)+F.Pow(x));
else return res+(res*base);
}
void solve(){
fre(tour);
cin>>n;
Rep(i,1,n){ cin>>(s+1); Rep(j,1,n)F.a[i][j]=(s[j]=='Y'); }
cin>>K>>Mod;
if(K==1)return cout<<0<<"\n",void();
Calc(K-1).Calc();
cout<<ans<<"\n";
}
int main (){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);return solve(),0; }