CSP模拟<反思> (16~20)
csp模拟16#
魔法仪式#
考虑经典的分治解决区间数数题的做法,对于一个区间,取中点,计算左端点在中点左边且右端点在中点右边的方案数,之后递归分治,即可求得答案。
考虑枚举中点后怎么计算,分开考虑最大值在左边和在右边的情况,以在左边的情况为例,从中点向左枚举左端点,不断维护右端点的可选范围(只需要保证最大值在左边),同时维护数组num[k]表示当前从中点到右边余数为k的方案数,这样对于每个左端点,只要在num中查询对应的值。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=3*1e5+10;
const int M=3*1e6+10;
int a[N];
int smod[M];
int tot;
int fk[M];
long long ans=0;
int n,k;
void solve(int l,int r){
if(l==r) return;
int mid=(l+r)/2;
int suml=0,ma=-1,sumr=0;
int j=mid;
tot=0;
for(int i=mid;i>=l;i--){
suml+=a[i];
ma=max(ma,a[i]);
int op=1;
while(j<r && a[j+1]<ma){
j++;
sumr+=a[j];
smod[sumr%k]++;
fk[++tot]=sumr%k;
}
ans+=smod[(k-(suml-ma)%k)%k];
}
for(int i=1;i<=tot;i++){
smod[fk[i]]=0;
}
ma=-1,sumr=0,suml=0;
j=mid+1;
tot=0;
for(int i=mid+1;i<=r;i++){
sumr=sumr+a[i];
ma=max(ma,a[i]);
while(j>l && a[j-1]<=ma){
j--;
suml+=a[j];
smod[suml%k]++;
fk[++tot]=suml%k;
}
ans+=smod[(k-(sumr-ma)%k)%k];
}
for(int i=1;i<=tot;i++){
smod[fk[i]]=0;
}
solve(l,mid);
solve(mid+1,r);
}
signed main(){
scanf("%lld%lld",&n,&k);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
solve(1,n);
printf("%lld",ans);
}
这里说一下第负一题:
第负一题#
首先
可以从区间中点向左写一个
枚举左端点
区间
如果
所以将所有的
这题还是强调一个分离变量的技巧,比较大小的时候把和
具体就是先扫右侧,排序,求右侧前缀,再扫左侧,扫的过程中二分查找点,然后计算贡献。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=998244353;
const int N=2*1e5+10;
int a[N];
int ans=0;
int f[N][2][2],g[N][2],cf[N],gf[N];
int sum1[N],sum2[N];
struct lhx{
int data,id;
}d[N];
bool amp(lhx x,lhx y){
return x.data<y.data;
}
int ask(int x,int ls,int rs){
int l=ls,r=rs;
while(l<r){
int mid=(l+r+1)/2;
if(d[mid].data<=x) l=mid;
else r=mid-1;
}
return l;
}
void solve(int l,int r){
if(l==r){
ans=(ans+a[l])%mod;
return;
}
int anss=ans;
int mid=(l+r)/2;
f[mid+1][0][0]=f[mid+1][0][1]=f[mid+1][1][0]=0,f[mid+1][1][1]=a[mid+1];
g[mid+1][0]=f[mid+1][0][0];
g[mid+1][1]=f[mid+1][1][1];
d[mid+1].data=g[mid+1][0]-max(g[mid+1][0],g[mid+1][1]);
d[mid+1].id=mid+1;
for(int i=mid+2;i<=r;i++){
f[i][0][0]=max(f[i-1][0][0],f[i-1][0][1]);
f[i][1][0]=max(f[i-1][1][0],f[i-1][1][1]);
f[i][0][1]=f[i-1][0][0]+a[i];
f[i][1][1]=f[i-1][1][0]+a[i];
g[i][0]=max(f[i][0][0],f[i][0][1]);
g[i][1]=max(f[i][1][0],f[i][1][1]);
d[i].data=g[i][0]-max(g[i][0],g[i][1]);
d[i].id=i;
}
sort(d+mid+1,d+r+1,amp);
sum1[mid]=sum2[mid]=sum1[r+1]=sum2[r+1]=0;
for(int i=mid+1;i<=r+1;i++){
sum1[i]=sum1[i-1]+g[d[i].id][0];
sum2[i]=sum2[i-1]+max(g[d[i].id][0],g[d[i].id][1]);
}
f[mid][0][0]=f[mid][0][1]=f[mid][1][0]=0,f[mid][1][1]=a[mid];
g[mid][0]=f[mid][0][0];
g[mid][1]=f[mid][1][1];
int j=ask(g[mid][0]-g[mid][1],mid,r);
ans=(ans+g[mid][0]*(j-mid)%mod+sum2[j]+sum1[r]-sum1[j]+g[mid][1]*(r-j)%mod+mod)%mod;
for(int i=mid-1;i>=l;i--){
f[i][0][0]=max(f[i+1][0][0],f[i+1][0][1]);
f[i][1][0]=max(f[i+1][1][0],f[i+1][1][1]);
f[i][0][1]=f[i+1][0][0]+a[i];
f[i][1][1]=f[i+1][1][0]+a[i];
g[i][0]=max(f[i][0][0],f[i][0][1]);
g[i][1]=max(f[i][1][0],f[i][1][1]);
int j=ask(g[i][0]-g[i][1],mid,r);
ans=(ans+g[i][0]*(j-mid)%mod+sum2[j]+sum1[r]-sum1[j]+g[i][1]*(r-j)%mod+mod)%mod;
}
solve(l,mid),solve(mid+1,r);
}
signed main(){
int n;
scanf("%lld",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
solve(1,n);
cout<<ans<<endl;
}
/*
10
850534838 749655434 745817507 991867417 645519349 373697182 427765279 182404140 260664174 366393413
5
1 3 3 2 4
*/
独特的数字#
数位状压dp,
点击查看代码
__int128 solve(__int128 op,__int128 zt,bool limit,__int128 fk){
if(!op) return 1;
if(!limit && dp[op][zt][fk]!=-1) return dp[op][zt][fk];
__int128 up=limit?num[op]:9;
__int128 ans=0;
for(__int128 i=0;i<=up;i++){
if(fk==1 && i==0){
ans+=solve(op-1,zt,limit&&i==up,1);
continue;
}
if(zt&(1<<i)) continue;
__int128 s=(zt|(1<<i));
ans+=solve(op-1,s,limit&&i==up,0);
}
if(!limit) dp[op][zt][fk]=ans;
return ans;
}
__int128 ask(__int128 k){
if(k<0) return 0;
__int128 ans=0;
while(k){
num[++ans]=k%10;
k/=10;
}
return solve(ans,0,1,1);
}
__int128 check(__int128 x){
__int128 l=0,r=17647868272689243559ull;
while(l<r){
__int128 mid=(l+r)/2;
if(ask(mid)>=x) r=mid;
else l=mid+1;
}
if(r>=M) return -1;
return l;
}
csp模拟17#
选举#
可以想到莫队+线段树维护区间最大,复杂度
正解:回滚莫队里套一个分块,可以将修改变为
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
int a[N],b[N];
struct asd{
int l,r,sl,sr;
int id;
}p[N];
int t1,t2;
int ln[N],rn[N];
int lm[N],rm[N];
int sum[N],c[N],sum1[N],c1[N];
int sum2[N],c2[N];
int posn[N],posm[N];
int cnt[N];
int data[N];//最终答案
bool amp(asd a,asd b){
if(posn[a.l]==posn[b.l]){
return a.r<b.r;
}
return posn[a.l]<posn[b.l];
}
void add(int x){
c[a[x]]+=b[x];
c2[a[x]]=c[a[x]];
sum[posm[a[x]]]=max(sum[posm[a[x]]],c[a[x]]);
sum2[posm[a[x]]]=sum[posm[a[x]]];
}
void add1(int x){
c[a[x]]+=b[x];
sum[posm[a[x]]]=max(sum[posm[a[x]]],c[a[x]]);
}
void dele1(int x){
c[a[x]]=c2[a[x]];
sum[posm[a[x]]]=sum2[posm[a[x]]];
}
int query(int x,int y){
int l=posm[x],r=posm[y];
int ma=0;
if(l==r){
for(int i=x;i<=y;i++) ma=max(ma,c[i]);
}
else{
for(int i=l+1;i<=r-1;i++) ma=max(ma,sum[i]);
for(int i=x;i<=rm[l];i++) ma=max(ma,c[i]);
for(int i=lm[r];i<=y;i++) ma=max(ma,c[i]);
}
return ma;
}
signed main(){
int n,m,Q;
scanf("%lld%lld%lld",&n,&m,&Q);
t1=sqrt(n);t2=sqrt(m);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
for(int i=1;i<=n;i++){
scanf("%lld",&b[i]);
}
for(int i=1;i<=Q;i++){
scanf("%lld%lld%lld%lld",&p[i].l,&p[i].r,&p[i].sl,&p[i].sr);
p[i].id=i;
}
for(int i=1;i<=t1;i++){
ln[i]=(i-1)*t1+1;
rn[i]=t1*i;
}
if(rn[t1]<n) t1++,ln[t1]=rn[t1-1]+1,rn[t1]=n;
for(int i=1;i<=t1;i++){
for(int j=ln[i];j<=rn[i];j++){
posn[j]=i;
}
}
for(int i=1;i<=t2;i++){
lm[i]=(i-1)*t2+1;
rm[i]=i*t2;
}
if(rm[t2]<m) t2++,lm[t2]=rm[t2-1]+1,rm[t2]=m;
for(int i=1;i<=t2;i++){
for(int j=lm[i];j<=rm[i];j++){
posm[j]=i;
}
}
sort(p+1,p+Q+1,amp);
int l=1,r=0,block=0;
int ma=0;
for(int i=1;i<=Q;i++){
int s1=posn[p[i].l],s2=posn[p[i].r];
if(s1==s2){
int tmp=0;
for(int j=p[i].l;j<=p[i].r;j++){
if(a[j]>=p[i].sl && a[j]<=p[i].sr){
cnt[a[j]]+=b[j];
tmp=max(tmp,cnt[a[j]]);
}
}
for(int j=p[i].l;j<=p[i].r;j++){
cnt[a[j]]=0;
}
data[p[i].id]=tmp;
continue;
}
if(block^posn[p[i].l]){
memset(sum,0,sizeof(sum));
memset(c,0,sizeof(c));
memset(sum2,0,sizeof(sum2));
memset(c2,0,sizeof(c2));
l=rn[posn[p[i].l]]+1,r=rn[posn[p[i].l]];
ma=0,block=posn[p[i].l];
}
while(r<p[i].r) r++,add(r);
int ll=l;
while(ll>p[i].l) ll--,add1(ll);
int tmp=query(p[i].sl,p[i].sr);
while(ll<rn[posn[p[i].l]]+1) dele1(ll),ll++;
data[p[i].id]=tmp;
}
for(int i=1;i<=Q;i++){
printf("%lld\n",data[i]);
}
}
/*
5 3 3
1 3 2 3 2
1 2 1 1 2
1 4 1 3
1 4 1 2
2 3 1 1
*/
晚会#
思考三个人之间友好距离为
csp模拟19#
最烂,没有之一!!!
十年之约#
输出打错了,挂60;
可爱三小只#
空间开小了,挂50;
蛋糕塌了#
首先可以想暴力,
修改操作考虑利用数据结构维护,对于区间
我们维护一个
区间答案就是 :
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7;
const int N=6*1e5+10;
int base[N];
int ny;
int mgml(int x,int p){
int ans=1;
while(p){
if(p&1) ans=(ans*x)%mod;
x=(x*x)%mod;
p>>=1;
}
return ans;
}
struct asd{
int size,g,h,l,r;
int f;
}tr[N*4];
struct qwe{
int x,y;
}as[N*4];
int a[N*4],b[N*4],rk[N*4];
int tk[N];
int tot=0;
struct zxc{
int data,fk,kl;
}st[N];
bool flat[N];
void pushup(int p){
tr[p].size=tr[p*2].size+tr[p*2+1].size;
tr[p].f=((tr[p*2].f+tr[p*2+1].f)%mod+tr[p*2].h*tr[p*2+1].g%mod)%mod;
tr[p].g=(tr[p*2].g+tr[p*2+1].g*base[tr[p*2].size]%mod)%mod;
tr[p].h=(tr[p*2].h*base[tr[p*2+1].size]%mod+tr[p*2+1].h)%mod;
}
void build(int p,int l,int r){
tr[p].l=l,tr[p].r=r;
if(l==r){
if(flat[l]){
tr[p].size=1;
tr[p].f=0;
tr[p].g=tr[p].h=rk[l]*ny%mod;
}
return;
}
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
pushup(p);
}
void change(int p,int wh,int v){
if(tr[p].l==tr[p].r){
if(v==0){
tr[p].size=0;
tr[p].f=tr[p].g=tr[p].h=0;
}
else{
tr[p].size=1;
tr[p].f=0;
tr[p].g=tr[p].h=rk[wh]*ny%mod;
}
return;
}
int mid=(tr[p].l+tr[p].r)/2;
if(wh<=mid) change(p*2,wh,v);
else change(p*2+1,wh,v);
pushup(p);
}
bool amp(zxc a,zxc b){
return a.data<b.data;
}
int p[N*4];
int n;
void init(){
base[0]=1;
for(int i=1;i<=n;i++){
base[i]=base[i-1]*2%mod;
}
for(int i=1;i<=n;i++){
base[i]=mgml(base[i],mod-2);
}
ny=mgml(2,mod-2);
}
inline int read(){
int x(0);bool f(0);char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar()) f^=ch=='-';
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);
return f?x=-x:x;
}
inline void write(int x){
x<0?x=-x,putchar('-'):0;static short Sta[50],top(0);
do{Sta[++top]=x%10;x/=10;}while(x);
while(top) putchar(Sta[top--]|48);
putchar('\n');
}
signed main(){
n=read();
for(int i=1;i<=n;i++){
a[i]=read();
st[++tot].data=a[i];
st[tot].kl=i;
}
init();
int q;
q=read();
for(int i=1;i<=q;i++){
as[i].x=read(),as[i].y=read();
st[++tot].data=as[i].y;
st[tot].fk=i;
}
sort(st+1,st+tot+1,amp);
for(int i=1;i<=tot;i++){
rk[i]=st[i].data;
if(st[i].kl){
p[st[i].kl]=i;
flat[i]=1;
}
if(st[i].fk){
tk[st[i].fk]=i;
}
}
build(1,1,tot);
write(tr[1].f);
for(int i=1;i<=q;i++){
change(1,p[as[i].x],0);
change(1,tk[i],1);
p[as[i].x]=tk[i];
write(tr[1].f);
}
}
/*
4
3 4 5 5
4
1 5
2 5
3 5
4 5
*/
西安行#
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7;
const int N=1e7+10;
int n,m;
struct asd{
int s[5][5];
int l,r;
}a,b,f,c;
int d[N];
asd mul(asd s1,asd s2){
asd z;
memset(z.s,0,sizeof(z.s));
for(int i=1;i<=s1.r;i++){
for(int j=1;j<=s2.l;j++){
for(int k=1;k<=s1.l;k++){
z.s[j][i]+=s1.s[k][i]*s2.s[j][k]%mod;
z.s[j][i]%=mod;
}
}
}
z.l=s2.l;
z.r=s1.r;
return z;
}
asd mgml(asd x,int p){
asd z;
memset(z.s,0,sizeof(z.s));
for(int i=1;i<=3;i++) z.s[i][i]=1;
z.l=z.r=3;
while(p){
if(p&1) z=mul(z,x);
x=mul(x,x);
p>>=1;
}
return z;
}
signed main(){
scanf("%lld%lld",&n,&m);
for(int i=1;i<=m;i++){
scanf("%lld",&d[i]);
}
a.l=a.r=b.l=b.r=c.l=c.r=3;
a.s[1][1]=1,a.s[1][2]=0,a.s[1][3]=1;
a.s[2][1]=2,a.s[2][2]=1,a.s[2][3]=2;
a.s[3][1]=1,a.s[3][2]=1,a.s[3][3]=2;
b.s[1][1]=1,b.s[1][2]=0,b.s[1][3]=0;
b.s[2][1]=2,b.s[2][2]=1,b.s[2][3]=0;
b.s[3][1]=1,b.s[3][2]=1,b.s[3][3]=1;
f.l=3,f.r=1;
f.s[1][1]=1;
f.s[2][1]=2;
f.s[3][1]=1;
d[0]=0;
for(int i=1;i<=m;i++){
if(d[i]-d[i-1]>1)f=mul(f,mgml(a,d[i]-d[i-1]-1));
f=mul(f,b);
}
if(d[m]<n-1){
if(n-1-d[m]>0){
f=mul(f,mgml(a,n-1-d[m]));
}
}
int ans=0;
cout<<f.s[3][1];
}
csp模拟20#
赞颂太阳#
看到与多个字符串长度有关,就可以想到AC自动机,然后按套路列出方程,
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=200005;
int a[N];
int b[N*2];
struct zxc{
int op,b,c,d;
}g[N];
int cnt=0;
int c[N*4];
int lowbit(int x){
return x&(-x);
}
void add(int wh,int v){
if(wh==0) return;
for(;wh<=cnt;wh+=lowbit(wh)) c[wh]+=v;
}
int ask(int wh){
int ans=0;
for(;wh;wh-=lowbit(wh)) ans+=c[wh];
return ans;
}
struct asd{
int l,r;
}kk[N];
int main(){
freopen("darkteam.in","r",stdin);
freopen("darkteam.out","w",stdout);
int n,m;
scanf("%d%d",&n,&m);
b[++cnt]=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
b[++cnt]=a[i];
}
for(int i=1;i<=m;i++){
int op,x,y;
scanf("%d",&g[i].op);
if(g[i].op==1){
scanf("%d",&g[i].b);
b[++cnt]=g[i].b;
}
else{
scanf("%d%d",&g[i].c,&g[i].d);
b[++cnt]=g[i].d;
}
}
sort(b+1,b+cnt+1);
int tot=unique(b+1,b+cnt+1)-(b+1);
for(int i=0;i<=n;i++){
int s1=lower_bound(b+1,b+tot+1,a[i])-(b);
int s2=lower_bound(b+1,b+tot+1,a[i+1])-(b);
int l=min(s1,s2)+1,r=max(s1,s2);
add(l,1),add(r+1,-1);
}
for(int i=1;i<=m;i++){
if(g[i].op==1){
int s1=lower_bound(b+1,b+tot+1,g[i].b)-(b);
int ans;
ans=ask(s1);
cout<<ans/2<<endl;
}
else{
int s1=lower_bound(b+1,b+tot+1,a[g[i].c-1])-(b);
int s2=lower_bound(b+1,b+tot+1,a[g[i].c])-(b);
int s3=lower_bound(b+1,b+tot+1,a[g[i].c+1])-(b);
int s4=lower_bound(b+1,b+tot+1,g[i].d)-(b);
a[g[i].c]=g[i].d;
int l=min(s1,s2)+1,r=max(s1,s2);
add(l,-1),add(r+1,1);
l=min(s2,s3)+1,r=max(s2,s3);
add(l,-1),add(r+1,1);
l=min(s4,s1)+1,r=max(s4,s1);
add(l,1),add(r+1,-1);
l=min(s4,s3)+1,r=max(s3,s4);
add(l,1),add(r+1,-1);
}
}
}
幽邃主教群#
对于相邻的两个数
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=200005;
int a[N];
int b[N*2];
struct zxc{
int op,b,c,d;
}g[N];
int cnt=0;
int c[N*4];
int lowbit(int x){
return x&(-x);
}
void add(int wh,int v){
if(wh==0) return;
for(;wh<=cnt;wh+=lowbit(wh)) c[wh]+=v;
}
int ask(int wh){
int ans=0;
for(;wh;wh-=lowbit(wh)) ans+=c[wh];
return ans;
}
struct asd{
int l,r;
}kk[N];
int main(){
freopen("darkteam.in","r",stdin);
freopen("darkteam.out","w",stdout);
int n,m;
scanf("%d%d",&n,&m);
b[++cnt]=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
b[++cnt]=a[i];
}
for(int i=1;i<=m;i++){
int op,x,y;
scanf("%d",&g[i].op);
if(g[i].op==1){
scanf("%d",&g[i].b);
b[++cnt]=g[i].b;
}
else{
scanf("%d%d",&g[i].c,&g[i].d);
b[++cnt]=g[i].d;
}
}
sort(b+1,b+cnt+1);
int tot=unique(b+1,b+cnt+1)-(b+1);
for(int i=0;i<=n;i++){
int s1=lower_bound(b+1,b+tot+1,a[i])-(b);
int s2=lower_bound(b+1,b+tot+1,a[i+1])-(b);
int l=min(s1,s2)+1,r=max(s1,s2);
add(l,1),add(r+1,-1);
}
for(int i=1;i<=m;i++){
if(g[i].op==1){
int s1=lower_bound(b+1,b+tot+1,g[i].b)-(b);
int ans;
ans=ask(s1);
cout<<ans/2<<endl;
}
else{
int s1=lower_bound(b+1,b+tot+1,a[g[i].c-1])-(b);
int s2=lower_bound(b+1,b+tot+1,a[g[i].c])-(b);
int s3=lower_bound(b+1,b+tot+1,a[g[i].c+1])-(b);
int s4=lower_bound(b+1,b+tot+1,g[i].d)-(b);
a[g[i].c]=g[i].d;
int l=min(s1,s2)+1,r=max(s1,s2);
add(l,-1),add(r+1,1);
l=min(s2,s3)+1,r=max(s2,s3);
add(l,-1),add(r+1,1);
l=min(s4,s1)+1,r=max(s4,s1);
add(l,1),add(r+1,-1);
l=min(s4,s3)+1,r=max(s3,s4);
add(l,1),add(r+1,-1);
}
}
}
作者:bloss
出处:https://www.cnblogs.com/jinjiaqioi/p/17619315.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效