zr模拟赛 8 (dp)

zr模拟赛 8

你好我的朋友,现在我生病了,对不起。

23zr提高day8-测测你的计数水平

👌

首先断环为链,方法是枚举某一个点连的是那一条边。

接着设fi表示从左到右扫到i的时候所有区间都没有超过i的方案数。

然后发现如果当前新区间覆盖了两个相同颜色的点就寄了,但是没有就没事。

另外一种想法是令gi表示i之前一共能满足多少个合法的区间。

容易发现虽然决策不一样但是这个区间个数是确定的,因为如果我们把两个区间换成一个的话就寄了。

最后验证一下合法区间的数量是否等于n-1(第一个已经拿下了)

然后就做完了。

include<bits/stdc++.h>
using namespace std;\
using namespace std;
const int maxn=6e6+10;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
int a[maxn];
long long ans;
int pre[maxn],nxt[maxn];
int n;
const int mod=1e9+7;
int p[maxn];
int g[maxn];
int f[maxn];
void solve(int l,int r){
    int len=r-l+1;
    memset(pre,0,sizeof(pre));
    memset(nxt,0,sizeof(nxt));
    memset(f,0,sizeof(f));
    g[l-1]=1;
    for(int i=l;i<=r;i++){
        if(p[a[i]]) pre[i]=p[a[i]];
        p[a[i]]=i;
////		cout<<pre[i]<<" " ;
    }
    for(int i=1;i<=n;i++) p[i]=0;
    for(int i=l;i<=r;i++){
        f[i]=f[i-1];
        g[i]=g[i-1];
        if(pre[i])
		if(f[pre[i] - 1] + 1 > f[i]) 
		{
			f[i] = f[pre[i] - 1] + 1;
			g[i] = g[pre[i] - 1];
		}
		else if(f[pre[i] - 1] + 1 == f[i]) g[i] = (g[i] + g[pre[i] - 1]) % mod;
            
        cout<<f[i]<<" "<<a[i]<<" "<<g[i]<<endl;
    }
    if(f[r]==n-1 ) ans=(ans+g[r])%mod;
}
signed main(){
    n=read();
    for(int i=1;i<=n*3;i++){
        a[i]=read();
        a[i+3*n]=a[i];
    }
    a[1];
    int fir=0,sec=0;
    for(int i=2;i<=3*n;i++){
        if(a[i]==a[1]) fir?sec=i:fir=i;
    }
//    cout<<fir<<" "<<sec<<endl;
    solve(fir+1,3*n);
    solve(sec+1,fir+3*n-1);
	solve(2,sec-1);
    cout<<ans<<endl;
}

23zr提高day8-测测你的优化水平

首先把所有节点映射到一个二维坐标系上的(x,y)。

我们可以把操作看作两个扫描线,一个删掉了x>i的所有结点,另外一个删掉了y>j的所有结点。

然后我们定义dpi,j表示这个扫描线当前在(i,j)时候的最好答案。这个答案显然是确定的。

转移方程就是

dpi,j=min(dpi+1,j+xi,(y<yj+1)dpi+1,j+1+yi)

前缀和优化可以做到n2

这个东西呢你观察一下就发现如果y<yj+1的话我就直接加上yi不是的话就直接加上xi.

线段树优化一下就做完了。

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
const int maxn=2e5+10;
struct node{
    int x,y,i;
}d[maxn];
int g[maxn];
int n;
bool cmp(node a,node b){
    return a.x<b.x;
}
int f[maxn*4];
int lz[maxn*4];
int len;
void pushdown(int p){
    lz[p<<1]+=lz[p];
    lz[p<<1|1]+=lz[p];
    f[p<<1]+=lz[p];
    f[p<<1|1]+=lz[p];
    lz[p]=0;
}
void add(int p,int l,int r,int L,int R,int v){
//	cout<<p<<" "<<l<<" "<<r<<" "<<L<<" "<<R<<" "<<v<<endl;
    if(L>R) return ;
//    if(f[p]>=0x3f3f3f3f) return ;
    if(L<=l&&r<=R){
        f[p]+=v;
//        cout<<f[p]<<" "<<v<<endl;
        lz[p]+=v;
        return ;
    }
    if(lz[p]) pushdown(p);
    int mid=(l+r)>>1;
    if(mid>=L) add(p<<1,l,mid,L,R,v);
    if(mid<R) add(p<<1|1,mid+1,r,L,R,v);
    f[p]=min(f[p<<1],f[p<<1|1]);
//   	cout<<f[p]<<" "<<l<<" "<<r<<" "<<L<<" "<<R<<" "<<v<<endl;
}
int get(int p,int l,int r,int L,int R){
    if(L<=l&&r<=R){
        return f[p];
    }
    if(lz[p]) pushdown(p);
    int mid=(l+r)>>1;
    int cnt=LLONG_MAX;
    if(mid>=L) cnt=min(cnt,get(p<<1,l,mid,L,R));
    if(mid<R) cnt=min(cnt,get(p<<1|1,mid+1,r,L,R));
    return cnt;
   
}
void insert(int p,int l,int r,int x,int v){
    if(l==r) {
		f[p]=v;
        return ;
    }
    pushdown(p);
    int mid=(l+r)>>1;
    if(mid>=x) insert(p<<1,l,mid,x,v);
    else insert(p<<1|1,mid+1,r,x,v);
    f[p]=min(f[p<<1],f[p<<1|1]);
}
signed main(){
    n=read();
    for(int i=1;i<=n;i++){
        d[i].x=read(),d[i].y=read();
        g[i]=d[i].y;
    }
    sort(d+1,d+n+1,cmp);
    g[n+1]=0;
    sort(g+1,g+n+2);
    memset(f,0x3f,sizeof(f));
    len=unique(g+1,g+n+2)-g-1;
//    for(int i=1;i<=len;i++) cout<<g[i]<<" ";
    for(int i=1;i<=n;i++){
        d[i].i=lower_bound(g+1,g+len+1,d[i].y)-g;
//        cout<<d[i].i<<" "<<d[i].y<<endl;
    }
    insert(1,1,len,1,0);
    for(int i=1;i<=n;i++){
        int y=d[i].i;
//        cout<<d[i].i<<endl;
        int v=get(1,1,len,1,d[i].i)+d[i].x;
//        insert(1,1,n,d[i].i,v);
//        cout<<2<<endl;
        add(1,1,len,d[i].i+1,len,d[i].x);
//        cout<<d[i].i+1<<" "<<len<<" "<<d[i].x<<endl;
//        cout<<3<<endl;
        add(1,1,len,1,d[i].i,d[i].y);
//        cout<<1<<" "<<d[i].i<<" "<<d[i].y<<endl;
//        cout<<4<<endl;
		insert(1,1,len,d[i].i,v);
//		cout<<d[i].i<<endl;
//		for(int j=1;j<=len;j++){
//			cout<<get(1,1,len,j,j)<<" ";
//		}
//		cout<<endl;
    }
    cout<<get(1,1,n,1,n)<<endl;
}

由于这一题调试了很久

所以把经验写在下面:

1.静态调试,注意线段树参数

2.return后面不能写东西

3.想好再写,思想是指导行动的方针

大道理讲完了,明天见,谢谢大家。

posted @   狐适之  阅读(27)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示