首页 > 其他分享 >CF练习题18

CF练习题18

时间:2023-11-03 11:55:21浏览次数:35  
标签:练习题 return int 18 CF dfs up minl mod

这次的题都是什么怪物!!!

Short Colorful Strip

因为 \(n=m\),所以最终的形态一定是 \(n\) 的一个排列。

根据题意,发掘几个性质:

  1. 一个区间染色,一定最先对其中颜色最小的染色。
  2. 染色要求覆盖的点颜色完全相同。

对于第一次来说,先找到颜色为 \(1\) 的点,位置是 \(p\)。

染色的区间是 \([l,r]\),\(l\le p\le r\)。

所以我们可以把答案分成四个区间 \([1,l]\),\([l+1,p-1]\),\([p+1,r]\),\([r+1,n]\)

\(ans=\sum_{l=1}^{p-1}f_{1,l}\times f_{l+1,p-1}\times \sum_{r=p}^{n}f_{p+1,r}\times f_{r+1,n}\)

对于查询的每一个区间都可以用这种方法求得,所以做法就很显然了。

int n,m;
int a[N];
int f[505][505];
inline int dfs(int l,int r){
    if(~f[l][r])return f[l][r];
    if(l>=r)return f[l][r]=1;
    int p=l;
    up(i,l,r)if(a[i]<a[p])p=i;
    int ans1=0,ans2=0;
    up(i,l,p)ans1=(ans1+dfs(l,i-1)*dfs(i,p-1)%mod)%mod;
    up(i,p,r)ans2=(ans2+dfs(p+1,i)*dfs(i+1,r)%mod)%mod;
    return f[l][r]=ans1*ans2%mod;
}
signed main(){
    memset(f,-1,sizeof f);
    n=read();m=read();
    up(i,1,m)a[i]=read();
    cout<<dfs(1,m);
    return 0;
}

Long Colorful Strip

似乎可以用同样的做法,对于每一种颜色,找出它 最左端的位置和最右端的位置,枚举 \(l,r\) 然后把当前区间分成五段,进行区间 dp。

然后一看, \(m\le 10^6\) ,当场去世。

那么有没有什么优化呢,我们考虑一下对于一段颜色相同的区间,我们可以选择把其压缩成一个点,但是这样似乎优化的很玄学,想一想有没有什么性质可以利用。

考虑一下,我们每一次染色,似乎最多增加两个 \(c_i!=c_{i+1}\)。

所以如果压缩后的 \(m\le 2n\),可以直接判断不合法。

复杂度 \(m^3\),但是能过。

int n,m;
int a[N],t;
int f[1505][1505];
int L[1540],R[1050];
inline int dfs(int l,int r){
    if(~f[l][r])return f[l][r];
    if(l>r)return 1;
    int &val=f[l][r];
	val=0;
	int minl=a[l];
	up(j,l,r)minl=min(minl,a[j]);
	int p=-1;
	int ans1=1;
	up(j,l,r){
		if(a[j]==minl) {
			if(p!=-1)ans1=ans1*dfs(p+1,j-1)%mod;
			p=j;
		}
	}
	int lans=0;
	up(j,l,L[minl]){
        lans=(lans+dfs(l,j-1)*dfs(j,L[minl]-1)%mod)%mod;
    }
	int rans=0;
	up(j,R[minl],r){
        rans=(rans+dfs(R[minl]+1,j)*dfs(j+1,r)%mod)%mod;
    }
	return val=ans1*lans%mod*rans%mod;
}
signed main(){
    memset(f,-1,sizeof f);
    n=read();m=read();
    int x,pre=0;
    up(i,1,m){
        x=read();
        if(x!=pre)a[++t]=x;
        pre=x;
    }
    if(t>2*n){
        puts("0");
        return 0;
    }
    up(i,1,n){
        int l=t+1,r=0;
        up(j,1,t){
            if(a[j]==i){
                l=min(l,j);
                r=max(r,j);
            }
        }
        up(j,l,r){
            if(a[j]<i){
                puts("0");
                return 0;
            }
        }
        L[i]=l;R[i]=r;
    }
    cout<<dfs(1,t);
    return 0;
}

Palindrome

很经典的一道题和性质。

最长回文子序列等于原串和反串的最长公共子序列。

但是求 LCS 是 \(n^2\) 的。

思考一下,因为全是小写字母,所以如果字符串的长度大于 \(2600\) 那么一定有一个所有字符都相同的符合条件的串。

不然的话就直接输出 LCS。

int n;
string s,t;
int f[2600][2600];
char ans[5050],ans2[5050];
signed main(){
    cin>>s;
    n=s.size();
    t=s;
    reverse(t.begin(),t.end());
    s=" "+s;t=" "+t;
    if(n<=2600){
        up(i,1,n){
            up(j,1,n){
                if(s[i]==t[j]){
                    f[i][j]=f[i-1][j-1]+1;
                }
                else{
                    f[i][j]=max(f[i-1][j],f[i][j-1]);
                }
            }
        }
        int i=n,j=n;
	    while(f[i][j]>0){
	    	if(s[i]==t[j]){
                ans[f[i][j]]=s[i];
                i--, j--;
            }
		    else{
			    if(f[i][j]==f[i-1][j]) i--;
			    else j--;
		    }
	    }
        if(f[n][n]<100){
            printf("%s",ans+1);
            return 0;
        }
        else{
            int t=0;
            up(i,1,50)ans2[++t]=ans[i];
            dn(i,49,0)ans2[++t]=ans[f[n][n]-i];
            printf("%s",ans2+1);
        }
    }
    else{
        up(j,'a','z'){
            int t=0;
            up(i,1,n){
                if(s[i]==j)t++;
            }
            if(t>=100){
                up(i,1,100)putchar(j);
                return 0;
            }
        }
    }
    return 0;
}

Constrained Tree

首先,我们已经知道了这个东西的先序遍历的顺序。

想一想如何判断一个点是在左子树还是右子树。

可以对每一个点求左子树的最小值,最大值,右子树的最小值,最大值。

然后递归求解。

int n,m;
int Lmax[N],Rmax[N],Lmin[N],Rmin[N];
int cnt=0;
bool flag=0;
vector<int>res;
inline void dfs(int l,int r){
    if(flag) return;
    ++cnt;
    if(Lmax[l]){
        if(Lmin[l]<=cnt)flag=1;
        dfs(cnt+1,Lmax[l]);
    }
    res.push_back(l);
    if(Rmax[l]){
        if(Rmin[l]<=cnt)flag=1;
        dfs(cnt+1,max(Rmax[l],r));
    } 
    else if(cnt<r)dfs(cnt+1,r);
}
signed main(){
    n=read();m=read();
    up(i,1,n){
        Lmin[i]=n+1;
        Rmin[i]=n+1;
    }
    int x,y;
    char s[10];
    up(i,1,m){
        x=read();y=read();
        if(x>=y){
            puts("IMPOSSIBLE");
            return 0;
        }
        scanf("%s",s+1);
        if(s[1]=='L'){
            Lmax[x]=max(Lmax[x],y);
            Lmin[x]=min(Lmin[x],y);
        }
        else{
            Rmax[x]=max(Rmax[x],y);
            Rmin[x]=min(Rmin[x],y);
        }
    }
    dfs(1,n);
    if(!flag){
        for(auto x:res){
            cout<<x<<" ";
        }
    }
    else puts("IMPOSSIBLE");
    return 0;
}

来一张阿卡多:

image

再来一张沃尔特:

image

标签:练习题,return,int,18,CF,dfs,up,minl,mod
From: https://www.cnblogs.com/LiQXing/p/17807304.html

相关文章

  • 初学Bokeh:定义坐标轴范围【18】跬步
    初学Bokeh:定义坐标轴范围【18】跬步定义坐标轴范围为绘图绘制坐标轴时,Bokeh会自动确定每个坐标轴需要覆盖的范围,以便显示所有值。例如,如果您的y轴上的值介于2和17之间,Bokeh会自动创建一个范围从略低于2到略高于17的y轴。如果,需要手动定义轴的范围,请在调用figur......
  • CF1837E
    这是一道非常有意思的题。设\(n\)为当前队伍数量。下面对于每个队伍的“数值”不是编号,而是能力。(比如说这时编号为\(1\)的队伍能力为\(n\))。思路清晰的,我们发现在初始状态下,每两格一组,每组之间是互相独立的。然后我们当前已经确定了一些队伍的位置,只知道这些发现很难去计......
  • CF1861D
    废话:VP时T3思路不清晰,写了很久,然后这题没时间做了,赛后五分钟AC了(还好不是正赛,不然我会气死的)。所以做题前思路一定要清晰且严谨!思路:观察这个问题,发现如果\(l\)到\(r\)不是单调的,那么完全没必要一起乘。那么本题中的操作将会一整段一整段的进行,我们肯定会让段数尽可......
  • CF773A Success Rate 题解
    SuccessRate(提供二分做法)前言听说是史上最简单蓝题,做了一下。题意已知\(x,y,p,q\),通过只让\(y\)加\(1\)或\(x,y\)同时加\(1\),使得满足:\[\frac{x'}{y'}=\frac{p}{q}\]思考目标状态为\(\frac{p}{q}\),考虑到这是个比值,自然\(\frac{x'}{y'}=\frac{kp}{kp}\)。明显......
  • CF 随机做题
    CF18842C假设咱们钦定在\(x\)处取到最大值,则对于任意线段\(i\),若\(i\)覆盖点\(x\),则选中她会使得\(\maxa\leftarrow\maxa+1\),\(\mina\leftarrow\mina+y\),\(y\in\{0,1\}\),则对答案产生\(\ge0\)的贡献,故此时必然将所有线段\(i\)均选中。接下来咱们考......
  • CF1868B2 Candy Party (Hard Version) 题解
    Problem-1868B2-CodeforcesCandyParty(HardVersion)-洛谷相信大家已经看过SimpleVersion,这题和上题不同之处就在于如果\(b_i=2^x\),他可以被分解成\(2^x\)或\(2^{x+1}-2^x\),我们不妨起初固定一种方案,如果不满足条件后再把一部分换回去。我们强制钦定起......
  • CF227A Where do I Turn? 题解
    题目大意:\(A\),\(B\)在一条直线上。\(B\),\(C\)在一条直线上你从\(A\)走到了\(B\)去\(C\),问现在应该是直走、左转、还是右转。思路:分类讨论:分别求\(A\)到\(B\),\(B\)到\(C\)是什么方向,然后可得\(A\)到\(C\)的方向。Code:#include<bits/stdc++.h>usingnamesp......
  • CF333B题解
    分析发现只能跳\(n-1\)次,所以每个点一定是畅通无阻地抵达终点,所以有障碍的行和列放不了,并且每一个行或列最多放一个。因为同时跳,思考会不会跳到一起,发现如果不在正中间可以将起点放到另一头就不会跳到一起,如果在正中间就一定会跳到一起,所以正中间的行和列加一起最多只能放......
  • CF333A题解
    分析被除数一定,除数越小,商越大,所以选择合法的最小\(3_{x}\)。枚举指数即可,复杂度\(\mathcal{O(\log_{3}w)}\),\(w\)为值域\(1e18\),可以通过本题。代码#include<iostream>#defineintlonglongusingnamespacestd;constexprintMAXN(1000007);intf[MAXN];int......
  • nginx报错 [error] 612#4188: CreateFile() "C:\yjzx\nginx-1.24.0/logs/nginx.pid"
    背景无论是nginx-sstop还是nginx-sreload命令,都会出现这个错误。[error]612#4188:CreateFile()"C:\yjzx\nginx-1.24.0/logs/nginx.pid"failed(2:Thesystemcannotfindthefilespecified)查找logs下nginx.pid文件确实没有创建成功,在网上查找了下了解决办法。发......