20220919--CSP-S模拟7

A. 序列问题

发现本质是让求一个 \(i-a_i\) 的最长不下降子序列
需要满足以下三个条件:

\(\begin{cases} j<i \\ a_j<a_i \\ j-a_j<i-a_i\end{cases}\)

进行一个 \(\operatorname{CDQ}\) 即可

点击查看代码
#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<algorithm>
#define int long long
#define WR WinterRain
using namespace std;
const int WR=500100;
struct Query{
    int x,y,z,ans;
}ask[WR],tmp[WR];
int n,tot,ans;
int a[WR],pos[WR],v[WR];
int tree[WR];
int dp[WR];
bool vis[WR];
int read(){
    int s=0,w=1;
    char ch=getchar();
    while(ch>'9'||ch<'0'){
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=(s<<3)+(s<<1)+ch-'0';
        ch=getchar();
    }
    return s*w;
}
bool cmp1(Query x,Query y){
    return x.y<y.y;
}
bool cmp2(Query x,Query y){
    return x.x<y.x;
}
int lowbit(int x){
    return x&(-x);
}
void modify(int k,int val){
    for(int i=k;i<=n;i+=lowbit(i)){
        // cerr<<i<<endl;
        tree[i]=max(tree[i],val);
    }
}
void clr(int k){
    for(int i=k;i<=n;i+=lowbit(i)) tree[i]=0;
}
int query(int k){
    int res=0;
    for(int i=k;i;i-=lowbit(i)){
        // cerr<<i<<endl;
        res=max(res,tree[i]);
    }
    return res;
}
void CDQ(int l,int r){
    if(l==r) return;
    int mid=(l+r)>>1;
    CDQ(l,mid);
    sort(ask+mid+1,ask+r+1,cmp1);
    int i=l,j=mid+1;
    while(j<=r){
        while(i<=mid&&ask[i].y<=ask[j].y){
            modify(ask[i].x-ask[i].y,ask[i].ans);
            i++;
        }
        ask[j].ans=max(ask[j].ans,query(ask[j].z)+1);
        j++;
    }
    while(i>l){
        i--;
        clr(ask[i].x-ask[i].y);
    }
    sort(ask+mid+1,ask+r+1,cmp2);
    CDQ(mid+1,r);
    merge(ask+l,ask+mid+1,ask+mid+1,ask+r+1,tmp+l,cmp1);
    for(i=l;i<=r;i++) ask[i]=tmp[i];
}
signed main(){
    // freopen("sequence.in","r",stdin);
    // freopen("sequence.out","w",stdout);
    n=read();
    for(int i=1;i<=n;i++){
        int x=read();
        if(x>i) continue;
        ask[++tot]={i,i-x,x-1,1};
    }
    CDQ(1,tot);
    for(int i=1;i<=tot;i++) ans=max(ans,ask[i].ans);
    printf("%lld\n",ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

B. 钱仓

image
image

点击查看代码
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#define int long long
#define WR WinterRain
using namespace std;
const int WR=1001000;
int n;
int c[WR],sum,st;
int ans;
queue<int>q;
int read(){
    int s=0,w=1;
    char ch=getchar();
    while(ch>'9'||ch<'0'){
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=(s<<3)+(s<<1)+ch-'0';
        ch=getchar();
    }
    return s*w;
}
signed main(){
    // freopen("barn.in","r",stdin);
    // freopen("barn.out","w",stdout);
    n=read();
    for(int i=1;i<=n;i++) c[i]=c[n+i]=read();
    for(int i=1;i<=n;i++){
        sum+=c[i];
        if(sum<i){
            st=i+1;
            sum=i;
        }
    }
    // printf("%lld ",st);
    // int pos=st-1;
    // do{
    //     printf("%lld\n",pos);
    //     if(c[pos]==0) q.push(pos);
    //     else{
    //         while(c[pos]&&(!q.empty())){
    //             int u=q.front();q.pop();
    //             c[pos]--;
    //             ans+=(pos-u)*(pos-u);
    //         }
    //         if(!c[pos]) q.push(pos);
    //     }
    //     pos--;
    //     pos=(pos-1+n)%n+1;
    // }while(pos!=st-1);
    //好像只能顺时针
    for(int i=st+n-1;i>=st;i--){
        if(c[i]==0) q.push(i);
        else{
            while(c[i]&&(!q.empty())){
                int u=q.front();q.pop();
                c[i]--;
                ans+=(i-u)*(i-u);
            }
            if(!c[i]) q.push(i);
        }
    }
    printf("%lld\n",ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

C. 自然数

image

点击查看代码
#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#define int long long
#define WR WinterRain
using namespace std;
const int WR=1001000;
struct SegmentTree{
    int l,r,val,minval,lzy;
}tree[WR<<2];
int n,a[WR];
int plc[WR],nxt[WR],rec[WR];
bool vis[WR];
int ans;
int read(){
    int s=0,w=1;
    char ch=getchar();
    while(ch>'9'||ch<'0'){
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=(s<<3)+(s<<1)+ch-'0';
        ch=getchar();
    }
    return s*w;
}
void pushup(int k){
    tree[k].val=tree[k<<1].val+tree[k<<1|1].val;
    tree[k].minval=min(tree[k<<1].minval,tree[k<<1|1].minval);
}
void pushdown(int k){
    tree[k<<1].lzy=tree[k<<1|1].lzy=tree[k].lzy;
    tree[k<<1].minval=tree[k<<1|1].minval=tree[k].minval;
    tree[k<<1].val=tree[k].lzy*(tree[k<<1].r-tree[k<<1].l+1);
    tree[k<<1|1].val=tree[k].lzy*(tree[k<<1|1].r-tree[k<<1|1].l+1);
    tree[k].lzy=-1;
}
void build(int k,int l,int r){
    // cerr<<k<<" "<<l<<" "<<r<<endl;
    tree[k].l=l,tree[k].r=r;
    tree[k].lzy=-1;
    if(l==r){
        tree[k].val=tree[k].minval=rec[l];
        return;
    }
    int mid=(l+r)>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    pushup(k);
}
void modify(int k,int l,int r,int val){
    if(tree[k].l>=l&&tree[k].r<=r){
        tree[k].val=val*(tree[k].r-tree[k].l+1);
        tree[k].minval=tree[k].lzy=val;
        return;
    }
    if(tree[k].lzy!=-1) pushdown(k);
    int mid=(tree[k].l+tree[k].r)>>1;
    if(l<=mid) modify(k<<1,l,r,val);
    if(r>mid) modify(k<<1|1,l,r,val);
    pushup(k);
}
int query_mex(int k,int pos){
    if(tree[k].l==tree[k].r){
        if(tree[k].minval>=pos) return tree[k].l;
        else return n+1;
    }
    if(tree[k].lzy!=-1) pushdown(k);
    if(tree[k<<1|1].minval<pos) return query_mex(k<<1|1,pos);
    else return min(tree[k<<1|1].l,query_mex(k<<1,pos));
    return n+1;
}
signed main(){
    freopen("mex.in","r",stdin);
    freopen("mex.out","w",stdout);
    n=read();
    for(int i=1;i<=n;i++) a[i]=read(),nxt[i]=n+1;
    int pos=0;
    for(int i=1;i<=n;i++){
        if(a[i]<WR) vis[a[i]]=true;
        while(vis[pos]) pos++;
        ans+=pos;
        rec[i]=pos;
    }
    for(int i=1;i<=n;i++){
        if(a[i]<WR){
            nxt[plc[a[i]]]=i;
            plc[a[i]]=i;
        }
    }
    build(1,1,n);
    for(int i=1;i<n;i++){
        modify(1,i,i,0);
        int mex=query_mex(1,a[i]+1);
        if(mex<nxt[i]) modify(1,mex,nxt[i]-1,a[i]);
        ans+=tree[1].val; 
    }
    printf("%lld\n",ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

D. 环路

一眼考虑矩阵
可以给 \(i\)\(i+n\) 连边再给 \(i+n\)\(i+n\) 连边
这样你每次统计的答案就全部放到 \(i+n\) 上去了
然后就可以直接矩阵快速幂了

点击查看代码
#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#define int long long
#define WR WinterRain
using namespace std;
const int WR=205;
int n,m,mod;
struct Matrix{
	int num[WR][WR];
	Matrix(){memset(num,0,sizeof(num));}
	Matrix operator*(const Matrix &b)const{
		Matrix res;
		for(int i=1;i<=n*2;i++){
			for(int j=1;j<=n*2;j++){
				for(int k=1;k<=n*2;k++){
					res.num[i][j]=(res.num[i][j]+num[i][k]*b.num[k][j]%mod)%mod;
				}
			}
		}
		return res;
	}
}mtx,ans;
int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch>'9'||ch<'0'){
		if(ch=='-') w=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		s=(s<<1)+(s<<3)+ch-'0';
		ch=getchar();
	}
	return s*w;
}
signed main(){
    freopen("tour.in","r",stdin);
    freopen("tour.out","w",stdout);
    n=read();
    for(int i=1;i<=n;i++){
        char str[WR];
        scanf("%s",str+1);
        for(int j=1;j<=n;j++){
            if(str[j]=='Y') mtx.num[i][j]=1;
            else mtx.num[i][j]=0;
        }
		mtx.num[i][n+i]=1;
		mtx.num[n+i][n+i]=1;
    }
	// for(int i=1;i<=n*2;i++){
	// 	for(int j=1;j<=n*2;j++){
	// 		printf("%lld ",mtx.num[i][j]);
	// 	}
	// 	printf("\n");
	// }
	m=read(),mod=read();
	for(int i=1;i<=n*2;i++) ans.num[i][i]=1;
	while(m){
		if(m&1) ans=ans*mtx;
		mtx=mtx*mtx;
		m>>=1;
	}
	int res=0;
	for(int i=1;i<=n;i++) res=(res+ans.num[i][n+i])%mod;
	printf("%lld\n",res-n);
	return 0;
}
posted @ 2022-09-20 18:46  冬天丶的雨  阅读(45)  评论(0编辑  收藏  举报
Live2D