CQBZ Round 12
首先,在本次考试中,我深刻认识到了常数优化的重要性。
我决心改掉 #define int long long
的坏习惯。
我们不能保证评测机的速度,我们只能保证自己代码的优秀。`
同时我要下定决心更改自己的思维方式。
我发现自身在做题时应合理利用时间,创造价值,不能出现T6这种写2.5h没拿一分的情况了。
我的思维方式是存在问题的,每当想到了复杂度正确的做法就开写,没有考虑到实现的细节以及复杂度是否真正正确。
导致实现+调试时遇到巨大困难。
magic
注意到
复杂度
linear
设
设
bracket
坑题。数据很小,我们可以在
先用栈处理出每个括号的对应位置。
然后枚举每一对括号进行拆解。这里我们枚举括号的右端点,秉承先拆小括号的原则。
将没有被拆的括号看作一个整体,也即一个字符。
那么一个括号不能被拆的充要条件是:
- 左括号前有
*,/
- 括号内含有加减运算,注意我们将一个未被拆的括号看作一个元素
变号,前方是减号就变正负号,是除号就变乘除号。
void solve(){
cin>>a+1;
int n=strlen(a+1);
for(int i=1;i<=n;i++){
pos[i]=vis[i]=0;
if(a[i]=='(')s.push(i);
if(a[i]==')')pos[i]=s.top(),pos[s.top()]=i,s.pop();
}
for(int i=1;i<=n;i++){
if(a[i]==')'){
int tag=0;
for(int j=pos[i]+1;j<i;j++){
if(a[j]=='('&&vis[j]==0)j=pos[j]+1;
if(a[j]=='+'||a[j]=='-')tag=1;
}
if(a[i+1]=='*'||a[i+1]=='/'||a[pos[i]-1]=='*'||a[pos[i]-1]=='/'){
if(tag)continue;
}
vis[i]=vis[pos[i]]=1;
if(a[pos[i]-1]=='-'){
for(int j=pos[i]+1;j<i;j++){
if(a[j]=='('&&vis[j]==0)j=pos[j]+1;
if(a[j]=='+')a[j]='-';
else if(a[j]=='-')a[j]='+';
}
}
if(a[pos[i]-1]=='/'){
for(int j=pos[i]+1;j<i;j++){
if(a[j]=='('&&vis[j]==0)j=pos[j]+1;
if(a[j]=='*')a[j]='/';
else if(a[j]=='/')a[j]='*';
}
}
}
}
for(int i=1;i<=n;i++){
if(!vis[i])cout<<a[i];
}
cout<<"\n";
}
treasure
简单的问题,显然我们是贪心地将路径的前面改为 a
。我们计算 a
的操作次数。
有
然后
成功将问题化为
现在考虑求解这个问题。朴素的想法的BFS,虽然数据没卡,但可以被卡——复杂度是错的。
有一个显然的性质是,对于所有字符串的第
这启发我们依次拼出每个字符。可以动态维护最优集合,设
设当前在拼第
这样我们就可以
//We can make the k become 0 easily.
//How to do it when the k is equal to 0?
/*
One naive views is to use DP.But comparing two string needs O(n).
Can we speed it?
Maybe we can use the MIM.Let it meet in the middle.
Through it,we can make the n reduce to the middle of before.
But the cost?
However,any act only be the (i+j-1)th.
So,We can make the set S to achieve it.
*/
void init(){
cin>>n;int k;cin>>k;
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)cin>>a[i][j];
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++){
s[i][j]=0x3f3f3f3f;
if(i==1&&j==1){
s[i][j]=(a[1][1]!='a');
if(s[i][j]<=k)a[i][j]='a'; continue;
}
if(i>1)s[i][j]=min(s[i][j],s[i-1][j]);
if(j>1)s[i][j]=min(s[i][j],s[i][j-1]);
s[i][j]+=(a[i][j]!='a');
if(s[i][j]<=k)a[i][j]='a';
}
f[1][1]=1;ans[2]=a[1][1];
for(int k=3;k<=(n<<1);k++){
char x='z';
for(int i=1;i<k;++i){
if(k-i>n)continue;
if(i>n)continue;
if(f[i-1][k-i]|f[i][k-i-1])x=min(x,a[i][k-i]);
}
for(int i=1;i<k;++i){
if(k-i>n)continue;
if(i>n)continue;
if(a[i][k-i]==x)f[i][k-i]=(f[i-1][k-i]|f[i][k-i-1]);
}
ans[k]=x;
}
for(int i=2;i<=(n<<1);i++)cout<<ans[i];
cout<<"\n";
}
summation
其实是一个蛮简单的数位DP,可惜我考场上选择了开“更好想”的T6。。。。
考场做T6的2h+应该是可以做出此题的。。。
最精妙的地方:对于每一位数字统计贡献。
我们考虑统计数字
首先考虑没有最高位限制的情况:
设
那么显然,我们枚举当前位填
,此时它排序后在 前面,则对 的贡献无影响,固有 ,此时再填一个 的贡献也同样毫无变化, ,但对于 而言,之前的所有 都向高位移动了一格,且加上了这个 ,固有 ,此时排序后在 后面,会导致 全部向高位移动一格,固有
再考虑一下最高位限制,我们只需要对
初始化:有最高位版本限制的
void solve(int d){
g[0][1]=d;
for(int i=0;i<n;i++){
f[i+1][0]=f[i+1][1]=g[i+1][0]=g[i+1][1]=0;
int x=a[i+1]-'0';
for(int j=0;j<2;j++){
for(int k=0;k<10;k++){
if(j&&k>x)break;
int s=(j&(k==x));
if(k<d)f[i+1][s]=(f[i+1][s]+f[i][j])%p,g[i+1][s]=(g[i+1][s]+g[i][j])%p;
if(k==d)f[i+1][s]=(f[i+1][s]+10ll*f[i][j]+g[i][j])%p,g[i+1][s]=(g[i+1][s]+g[i][j])%p;
if(k>d)f[i+1][s]=(f[i+1][s]+10ll*f[i][j])%p,g[i+1][s]=(g[i+1][s]+10ll*g[i][j])%p;
}
}
}
ans=(ans+f[n][1]+f[n][0])%p;
}
mid
注意到
这是区间第
求解区间第
显然这个区间端点可移动是很恶心的。
根据最初的分析,不难想到二分这个第
在这里,我最初的思想是,由于
这时候,问题变为贪心地找到一个区间
这三个值加起来,如果大于了
在代码上我是考虑对于每一个值域开主席树维护,标记永久化,具体做法就不详细说了,因为我挂了。
这引申出了一个重要的 Trick。
对于维护区间
内满足某类限制的数的个数 与区间长度进行操作的问题,也即维护与 有关的问题,可以将满足该类限制的数看做 1,不满足的看做0.
在这里,将
对于固定左/右端点的最大区间和问题,就是维护最大子段和里的向左向右子段和。
可以在主席树里进行维护。那么只需要
而对于这个怎么维护呢?开一颗主席树,最初所有点权值都是1,进行离散化,然后按照权值进行插入,在版本
时间复杂度为
细节很多,这里给出代码进行参考.
#include<bits/stdc++.h>
using namespace std;
#define N 500500
#define int long long
int id,rt[N<<1],lc[N<<5],rc[N<<5],lx[N<<5],s[N<<5],rx[N<<5],a[N],b[N],c[N],n,m,f;
void build(int &x,int l,int r){
x=++id;lx[x]=rx[x]=r-l+1;
s[x]=r-l+1;
if(l==r)return ;int mid=l+r>>1;
build(lc[x],l,mid);
build(rc[x],mid+1,r);
}
void pushup(int x){
lx[x]=max(lx[lc[x]],s[lc[x]]+lx[rc[x]]);
rx[x]=max(rx[rc[x]],s[rc[x]]+rx[lc[x]]);
s[x]=s[lc[x]]+s[rc[x]];
}
void updata(int &x,int p,int l,int r,int pos,int k){
x=++id;lc[x]=lc[p],rc[x]=rc[p],s[x]=s[p],lx[x]=lx[p],rx[x]=rx[p];
if(l==r){
s[x]=lx[x]=rx[x]=k;
return ;
}
int mid=l+r>>1;
if(pos<=mid)updata(lc[x],lc[p],l,mid,pos,k);
else updata(rc[x],rc[p],mid+1,r,pos,k);
pushup(x);
}
struct node{
int lx,rx,s;
};
node merge(node a,node b){
node c;c.s=a.s+b.s;
c.lx=max(a.lx,a.s+b.lx);
c.rx=max(b.rx,b.s+a.rx);return c;
}
node find(int x,int l,int r,int L,int R){
// cout<<"find : "<<l<<" "<<r<<" "<<lx[x]<<" "<<s[x]<<" "<<rx[x]<<"\n";
if(L<=l&&r<=R)return (node){lx[x],rx[x],s[x]};
int mid=l+r>>1;
if(L<=mid&&mid<R)return merge(find(lc[x],l,mid,L,R),find(rc[x],mid+1,r,L,R));
if(L<=mid)return find(lc[x],l,mid,L,R);
return find(rc[x],mid+1,r,L,R);
}
vector<int>g[N];
void init(){
cin>>f>>n;
for(int i=1;i<=n;i++)cin>>a[i],b[i]=a[i];
sort(b+1,b+n+1);m=unique(b+1,b+n+1)-b-1;
for(int i=1;i<=n;i++)c[i]=lower_bound(b+1,b+m+1,a[i])-b;
// for(int i=1;i<=n;i++)cout<<c[i]<<" ";cout<<"\n";
for(int i=1;i<=n;i++)g[c[i]].push_back(i);
build(rt[1],1,n);
int pq=m;
for(int i=2;i<=m;i++){
++pq;rt[pq]=rt[i-1];
for(auto x:g[i-1]){
updata(rt[pq+1],rt[pq],1,n,x,-1);++pq;
}
rt[i]=rt[pq];
}
}
int query(int a,int b,int c,int d){
// cout<<a<<" "<<b<<" "<<c<<" "<<d<<"\n";
++a,++b,++c,++d;
int l=1,r=m;
while(l<r){
int mid=l+r+1>>1;
node you=find(rt[mid],1,n,a,b-1),arenot=find(rt[mid],1,n,b,c),alone=find(rt[mid],1,n,c+1,d);
// cout<<mid<<" "<<you.rx<<" "<<arenot.s<<" "<<alone.lx<<"\n";
you.rx=max(0ll,you.rx);alone.lx=max(0ll,alone.lx);
if(you.rx+arenot.s+alone.lx>=0){
l=mid;
}
else r=mid-1;
}
return l;
}
int in[4];
signed main(){
// freopen("data.in","r",stdin);
// freopen("data.out","w",stdout);
ios::sync_with_stdio(false);
init();int lst=0;
int q;cin>>q;
while(q--){
for(int i=0;i<4;i++)cin>>in[i],in[i]=(in[i]+lst*f)%n;
sort(in,in+4);
lst=b[query(in[0],in[1],in[2],in[3])];
cout<<lst<<"\n";
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!