9.22-CSP-S模拟9
T1 最长上升子序列
这玩意是拍过去的,猜了一个小时结论,改一次拍一次。做法大概就是从小到达考虑还没放的数,如果当前最优最长上升子序列里有比它大的项,那么它可以塞到它后边,然后更新最优上升子序列,否则就塞到最后一个位置的前边。对于塞到前边的数,需要让他们降序排列,保证每一段最多只能给LIS贡献1
点击查看代码
#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 a[maxn],b[maxn];
int n,K;
vector<int>vec1[maxn],vec2[maxn];
bool vis[maxn];
void Sol(int x){
int pos=upper_bound(a+1,a+K+1,x)-a;
if(a[pos]>x){
a[pos]=x;
vec1[pos].push_back(x);
return;
}
pos-=2;
vec2[pos].push_back(x);
}
void solve(){
cin>>n>>K;
Rep(i,1,K)cin>>a[i],vis[a[i]]=true,b[i]=a[i];
Rep(i,1,n)if(!vis[i]){
Sol(i);
}
Rep(i,0,K){
if(!vec1[i].empty()){
sort(vec1[i].begin(),vec1[i].end());
for(auto it : vec1[i])cout<<it<<" ";
}
if(i<K){
vec2[i].push_back(b[i+1]);
if(!vec2[i].empty()){
sort(vec2[i].begin(),vec2[i].end());
reverse(vec2[i].begin(),vec2[i].end());
for(auto it : vec2[i])cout<<it<<" ";
}
}
}
}
int main (){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);return solve(),0; }
T2 独特序列
应该是最简单的题,考虑设 表示以 结尾,不考虑后边的数时的独特序列数量,维护 和 表示 上一次和下一次出现的位置。
对于 能转移到它的 需满足 ,到这里是个裸的三维偏序实际上已经可以直接莽 CDQ 了, 跑俩log轻轻松松,
但是实质上可能合法的 的位置是连续的,前两维已经保证了于是只需要再上个树限制第三维,随便莽个主席树就行了,码量甚至可能比 CDQ 还大?
点击查看代码
#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,Mod=998244353;
struct ZXS{
#define LCH tr[rt].lch
#define RCH tr[rt].rch
struct Tree{int lch,rch,val;}tr[maxn*40];
int tot;int root[maxn];
void Pushup(int rt){tr[rt].val=(tr[LCH].val+tr[RCH].val)%Mod;}
void Modify(int &rt,int p,int l,int r,int x,int w){
if(!rt)rt=++tot,tr[rt]=tr[p];
if(l==r)return tr[rt].val=(tr[rt].val+w)%Mod,void();
int mid=(l+r)>>1;
if(x<=mid){LCH=0;Modify(LCH,tr[p].lch,l,mid,x,w);}
else {RCH=0;Modify(RCH,tr[p].rch,mid+1,r,x,w);}
Pushup(rt);
}
int Query(int rt,int p,int l,int r,int s,int t){
if(!rt)return 0;
if(s<=l && t>=r)return (tr[rt].val-tr[p].val)%Mod;
int mid=(l+r)>>1,res=0;
if(s<=mid)res=Query(LCH,tr[p].lch,l,mid,s,t);
if(t>mid)res=(res+Query(RCH,tr[p].rch,mid+1,r,s,t))%Mod;
return res;
}
}T;
int n;
int a[maxn],pre[maxn],nxt[maxn],last[maxn];
int f[maxn];
/*void Debug(){
Rep(i,1,n)cerr<<pre[i]<<" ";cerr<<"\n";
Rep(i,1,n)cerr<<nxt[i]<<" ";cerr<<"\n";
Rep(i,1,n)cerr<<f[i]<<" ";cerr<<"\n";
}*/
void solve(){
cin>>n;
Rep(i,1,n){ cin>>a[i]; pre[i]=last[a[i]]; last[a[i]]=i; }
Rep(i,1,n)last[i]=n+1;
Dwn(i,n,1){ nxt[i]=last[a[i]];last[a[i]]=i; }
f[1]=1;
// T.Modify(T.root[0],T.root[0],0,n+1,0,1);
T.Modify(T.root[1],T.root[0],0,n+1,nxt[1],1);
Rep(i,2,n){
if(pre[i]==0){
f[i]=T.Query(T.root[i-1],T.root[pre[i]],0,n+1,i,n+1)+1;
}else f[i]=T.Query(T.root[i-1],T.root[pre[i]-1],0,n+1,i,n+1);
T.Modify(T.root[i],T.root[i-1],0,n+1,nxt[i],f[i]);
}
int ans=0;
Rep(i,1,n){
if(nxt[i]==n+1)ans=(ans+f[i])%Mod;
}
// Debug();
cout<<(ans+Mod)%Mod<<"\n";
}
#undef int
int main (){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);return solve(),0; }
T3 最大GCD
裸题,赛时脑子抽了写了个树状数组求前缀和,甚至连修改都没有。算法本身就是基于值域的,随便上个桶就能判了,赛时像个rz。
直接暴力去判能不能让所有数都能整除g,也就是让每个数都增加到离它最近的g的倍数,显然是可以按照g的倍数分成 段,每段分别算一下贡献就行。枚举倍数是一个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 pil pair<int,ll>
#define mair make_pair
#define fir first
#define sec second
using namespace std;
const int maxn=3e5+10;
int N;
int n;
ll Lim,Sum;
int a[maxn];
int ans=1;
pil sum[maxn];
void Check(){
ll ned=1LL*n*N-Sum;
if(ned<=Lim){
Lim-=ned;
cout<<((ll)N)+(Lim)/n<<"\n";
exit(0);
}else return;
}
bool Try(int x){
pil last=mair(0,0);
ll ned=0;
for(int j=1;(j-1)*x<N;++j){
pil res=sum[min(N,j*x)];
ned+=(1LL*(res.fir-last.fir)*j*x-res.sec+last.sec);
last=res;
if(ned>Lim)return false;
}
return ned<=Lim;
}
void solve(){
cin>>n>>Lim;Rep(i,1,n)cin>>a[i],N=max(a[i],N),Sum+=a[i];
Check();
Rep(i,1,n)sum[a[i]].fir++,sum[a[i]].sec+=a[i];
Rep(i,1,N)sum[i].fir+=sum[i-1].fir,sum[i].sec+=sum[i-1].sec;
Dwn(i,N-1,2)if(Try(i))return cout<<i<<"\n",void();
cout<<1<<"\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
#define lowbit(x) (x&-x)
using namespace std;
const int maxn=2e2+10,maxk=17,INF=0x3f3f3f3f;
int n,K;
int a[maxn];
vector<int>vec[maxn],Now;
int ans=INF;
int Rand(int l,int r){return l+(rand())%(r-l+1);}
void Check(){
Rep(i,1,n-K+1){
int res=0;
for(int j=0;j<K;++j){
res+=abs(Now[j]-(i+j));
}
ans=min(ans,res);
}
}
void Dfs(int step){
if(step>K)return Check();
for(auto it : vec[step]){
Now.push_back(it);
Dfs(step+1);
Now.pop_back();
}
}
void solve(){
srand(time(NULL));
cin>>n>>K;
Rep(i,1,n)cin>>a[i],vec[a[i]].push_back(i);
if(n==K)Dfs(1),cout<<ans/2<<"\n";
else cout<<Rand(0,2)<<"\n";
}
int main (){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);return solve(),0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义