补题--4(#605 Div.3)


网址: https://vjudge.net/contest/381166
codeforce的比赛网址: https://codeforces.com/contest/1272

A(div.3 F)

题意:就是输入两个a,b字符串,然后找到一个最短的c字符串,其中组成由a,b的子串。
这一题是第一题我也看没想好怎么做,哈哈哈,然后现在我看了比赛的代码也不是太懂,然后就又找了网上的代码。
网上代码:
分析:设 dp[i][j][z] 表示已经 匹配到 序列 a 的第 i 位,序列 b 的第 j 位,当前左括号比右括号多 z 个的最短长度(规则序列,从左往右左括号当然只能比右括号多),则最终答案是 dp[n][m][0] ( n=len(a) , m=len(b) ) – 转移状态:通过枚举左右括号
①: ( – 则 z+1,第 i , j 位若是 ‘(’ 加一,否则不加,dp[ii][jj][z+1]=dp[i][j][z]+1;
②: ) – 则 z -1,第 i , j 位若是 ‘)’ 加一,否则不加,dp[ii][jj][z- 1]=dp[i][j][z]+1;
注意要判断 z 的边界,因为要记录路径,所以,开个结构体同步更新就可以了。

#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
 
const int N = 200+5;
const int INF = 0X3F3F3F3F;
 
char a[N],b[N];
int  n,m;
int  dp[N][N][N];
vector<char>ans;
 
struct node
{
	int x,y,z; char c;
	node(int _x=0,int _y=0,int _z=0,char _c=0)
	{
		x=_x,y=_y,z=_z,c=_c;
	}
}p[N][N][N];
 
void bfs()
{
	memset(dp,INF,sizeof(dp));
	queue<node>que;
	que.push(node(0,0,0));
	dp[0][0][0]=0;
	while(!que.empty())
	{
		node top=que.front(); que.pop();
		
		int nx=top.x+(top.x<n&&a[top.x]=='(');
		int ny=top.y+(top.y<m&&b[top.y]=='(');
		int nz=top.z+1;
		if(nz<=200&&nz>=0&&dp[nx][ny][nz]==INF)
		{
			dp[nx][ny][nz]=dp[top.x][top.y][top.z]+1;
			p[nx][ny][nz]=node(top.x,top.y,top.z,'(');
			que.push(node(nx,ny,nz));
		}
		
		nx=top.x+(top.x<n&&a[top.x]==')');
	    ny=top.y+(top.y<m&&b[top.y]==')');
		nz=top.z-1;
		if(nz<=200&&nz>=0&&dp[nx][ny][nz]==INF)
		{
			dp[nx][ny][nz]=dp[top.x][top.y][top.z]+1;
			p[nx][ny][nz]=node(top.x,top.y,top.z,')');
			que.push(node(nx,ny,nz));
		} 
	}
}
 
int main()
{
	scanf("%s%s",a,b);
	n=strlen(a);
	m=strlen(b);
	bfs();
	node k=p[n][m][0];
	while(k.x>0||k.y>0||k.z>0)
	{
		ans.push_back(k.c);
		k=p[k.x][k.y][k.z];
	}
	ans.push_back(k.c);
	reverse(ans.begin(),ans.end());
	for(int i=0;i<ans.size();i++) printf("%c",ans[i]);
	puts("");
}

比赛中的代码:

#include<bits/stdc++.h>
using namespace std;
const int mxn=203,inf=mxn<<1;
char a[mxn],b[mxn];
int d[mxn][mxn][mxn],n,m,l;
int f[mxn][mxn][mxn];
void dg(int x,int y,int k){
    if(x==0&&y==0&&k==0){
        return;
    }
    if(f[x][y][k]==1){
        dg(x,y,k-1);
        putchar('(');
    } else if(f[x][y][k]==2){
        dg(x-1,y-1,k-1);
        putchar('(');
    } else if(f[x][y][k]==3){
        dg(x-1,y,k-1);
        putchar('(');
    } else if(f[x][y][k]==4){
        dg(x,y-1,k-1);
        putchar('(');
    } else if(f[x][y][k]==5){
        dg(x,y,k+1);
        putchar(')');
    } else if(f[x][y][k]==6){
        dg(x-1,y-1,k+1);
        putchar(')');
    } else if(f[x][y][k]==7){
        dg(x-1,y,k+1);
        putchar(')');
    } else if(f[x][y][k]==8){
        dg(x,y-1,k+1);
        putchar(')');
    } else printf("??????\n");
}
int main(){
    scanf("%s%s",a+1,b+1);
    n=strlen(a+1);
    m=strlen(b+1);
    l=max(m,n);
    for(int i=0;i<mxn;i++) for(int j=0;j<mxn;j++) for(int k=0;k<mxn;k++) d[i][j][k]=inf;
    for(int i=0;i<=l;i++){
        d[0][0][i]=i;
        f[0][0][i]=1;
    }
    for(int i=0;i<=n;i++) for(int j=0;j<=m;j++){
        if(i==0&&j==0) continue;
        for(int k=0;k<=l;k++){
            if(k>0){
                if(i&&j&&a[i]=='('&&b[j]=='('){
                    if(d[i-1][j-1][k-1]+1<d[i][j][k]){
                        d[i][j][k]=d[i-1][j-1][k-1]+1;
                        f[i][j][k]=2;
                    }
                }
                else if(i&&a[i]=='('){
                    if(d[i-1][j][k-1]+1<d[i][j][k]){
                        d[i][j][k]=d[i-1][j][k-1]+1;
                        f[i][j][k]=3;
                    }
                }
                else if(j&&b[j]=='('){
                    if(d[i][j-1][k-1]+1<d[i][j][k]){
                        d[i][j][k]=d[i][j-1][k-1]+1;
                        f[i][j][k]=4;
                    }
                }
            }
            if(i&&j&&a[i]==')'&&b[j]==')'){
                if(d[i-1][j-1][k+1]+1<d[i][j][k]){
                    d[i][j][k]=d[i-1][j-1][k+1]+1;
                    f[i][j][k]=6;
                }
            }
            else if(i&&a[i]==')'){
                if(d[i-1][j][k+1]+1<d[i][j][k]){
                    d[i][j][k]=d[i-1][j][k+1]+1;
                    f[i][j][k]=7;
                }
            }
            else if(j&&b[j]==')'){
                if(d[i][j-1][k+1]+1<d[i][j][k]){
                    d[i][j][k]=d[i][j-1][k+1]+1;
                    f[i][j][k]=8;
                }
            }
        }
        for(int k=1;k<=l;k++){
            if(d[i][j][k-1]+1<d[i][j][k]){
                d[i][j][k]=d[i][j][k-1]+1;
                f[i][j][k]=1;
            }
        }
        for(int k=l;k>=0;k--){
            if(d[i][j][k+1]+1<d[i][j][k]){
                d[i][j][k]=d[i][j][k+1]+1;
                f[i][j][k]=5;
            }
        }
    }
    return 0:
    }

B(div.3 D)

题意:就是删除一个数然后找到最长的单调递增的序列。
比赛中的最简代码:

#include <iostream>
#include <iomanip>
#define LL long long
using namespace std;
const int N=2e5+5;
int a[N];
int f[N],g[N];
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
		cin>>a[i];
	
	for(int i=1;i<=n;i++)
		f[i]=g[i]=1;
	
	for(int i=2;i<=n;i++)
	{
		if(a[i-1]<a[i]) f[i]=f[i-1]+1;
	}
	for(int i=n-1;i>0;i--)
	{
		if(a[i]<a[i+1]) g[i]=g[i+1]+1;
	}
	int ans=1;
	for(int i=1;i<=n;i++)
	{
		if(a[i+1]>a[i-1]||i==n) ans=max(ans,f[i-1]+g[i+1]);
		ans=max(ans,f[i]);
	}
	cout<<ans<<endl;
	return 0;
}
 

我比赛的代码:
只是在最后的时候有一点不一样,但大致意思是一样的。
思路:
首先这个题目应该是找到最长的递增序列,所以要找到前面最长的和后面最长的然后if(a[i]<a[i+2])说明去掉i+1号位置后,以i号位置为终点的最长递增序列的最后一个数a[i]小于以i+2号位置为起点的最长递增序列的第一个数a[i+2],然后这两部分就可以连接起来就最长了。

for(int i=1;i<=n-2;i++)
    {
        if(a[i]<a[i+2]){
            maxnn=max(maxnn,l[i]+r[i+2]);
        }
    }

C(div.3 A)

题意:大致意思就是三个数,可以分别对这三个数进行放大一个,或者放小一个,然后使两两分别进行取差的和到最小。
比赛中的最简形式:

 #include <iostream>
using namespace std;
int main() {
	int t;
	cin>>t;
	while (t--)
	{
		int a,b,c;
		cin>>a>>b>>c; 
		cout<<max(0, abs(a-b)+abs(a-c)+abs(b-c)-4)<<endl;
	}
}

思路:
在赛的时候我所得到的是(最大值的两倍-最小值的两倍-4)这个应该符合一部分的题目,但是还要参杂一定的条件,而且还要对他进行排序运算,而这个人的方法则是我的想法的简单版的感觉,但是我总是在绕圈子,而且根本不需要ll。
我的比赛时候的代码:

#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
int main()
{
    int q;
    ll a[3],sum;
    cin>>q;
    while(q--)
    {
        for(int i=1;i<=3;i++)
        {cin>>a[i];}
        sort(a+1,a+4);
        if(a[3]-a[2]<=1&&a[2]-a[1]<=1)
        sum=0;
        else
        sum=2*a[3]-2*a[1]-4;
        cout<<sum<<endl;}
        return 0;}

D(div.3 E)

题意:就是一个长度为n的序列a,他可以动,在i位置的时候可以向i+ai和i-a[i]动,然后到达一个位置j,最后造成ai和aj奇偶性不同。
思路:没有,看了大佬的也是看太懂,然后又找到博客
https://blog.csdn.net/Miaplacidus/article/details/103589010?utm_medium=distribute.pc_relevant.none-task-blog-baidujs-2

#include<bits/stdc++.h>
using namespace std;
const int maxn=200005;
int a[maxn],dist[maxn];
vector<int> G[maxn];
int main()
{
	memset(dist,-1,sizeof(dist));
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
		cin>>a[i];
	queue<int> QAQ;
	for(int i=1;i<=n;i++)//反向建边
	{
		if(i+a[i]<=n)
			G[i+a[i]].push_back(i);
		if(i-a[i]>=1)
			G[i-a[i]].push_back(i);
	}
	for(int i=1;i<=n;i++)//将所有能一步到位的预处理出来
	{
		int x=i+a[i];
		if(x<=n&&(a[x]^a[i])&1)//奇偶性不同
			dist[i]=1;
		x=i-a[i];
		if(x>=1&&(a[x]^a[i])&1)
			dist[i]=1;
		if(dist[i]==1)
			QAQ.push(i);
	}
	while(!QAQ.empty())
	{
		int x=QAQ.front();
		QAQ.pop();
		for(auto &v:G[x])
			if(dist[v]==-1)//这里没有能一步跳到奇偶性不同的点
			{
				dist[v]=dist[x]+1;
				QAQ.push(v);
			}
	}
	for(int i=1;i<=n;i++)
	{
		cout<<dist[i]<<' ';
	}
	return 0;
}

E(div.3 C)

题意:一个字符串s,仅由小写英文字母构成。他想打出所有连续非空子串。可是,他发现他的键盘坏了,只能打出26字母中的k个。请求出用这个坏掉的键盘,最多能打出多少个字符串s的连续非空子串。
思路:这个就是但是看懂了啥意思,但是呢不知道怎么去把他表示出来。然后看了两个人的代码,明白了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
char s[200005];
bool mp[30];
ll dp[200005];
int main()
{
	ll n,k;
	cin>>n>>k>>s+1;
	for(int i=0;i<k;i++)
	{
		char ch;
		cin>>ch;
		mp[ch-'a']=1;//先用mp记录下输入的字符串
	}
	ll ans=0;
	for(int i=1;i<=n;i++)
	{
		if(!mp[s[i]-'a'])
			dp[i]=i;
		else
			dp[i]=dp[i-1];
		ans+=dp[i];
	}
	cout<<n*(n+1)/2-ans<<endl;
	return 0;
}

#include <iostream>
using namespace std;
#define SIS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define endl '\n'
bool arr[26];
using ll = long long;
int main()
{
    SIS;
int chong;
    char ch;
    int n,k;
    cin >> n >> k;
    string s;
    cin >> s;
    for(int i=0;i<k;i++)
    {
        cin >> ch;
        arr[ch-'a']=true;
    }
    ll ans=0,cnt=0;
    for(int i=0;i<n;i++)
    {
        if(arr[s[i]-'a']) cnt++;
        else cnt=0;
        ans+=cnt;
    }
    cout << ans << endl;
    return 0;
}

F(div.3 B)

题意:就是走一个格子一个格子,可以像左像右或者向前向后一格,
对刚开始的步伐进行删减,最后走到(0,0)。
思路:这个题目就是先前向后一样多,然后向左向右一样的。所以就先计算一下那个多,那个少,就进行多填后者少补的计划就可以了。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<iomanip>
#include<cmath>
#include<cstring>
#include<string>
using namespace std;
typedef long long ll;
ll t,n,r,i,j,k,sum,ans,cnt,a,b,m,c,d;
const int maxn=100005;
char str[maxn],str1[maxn];
int main()
{
    ios::sync_with_stdio(false);
    cin>>t;
    while(t--)
    {
        cin>>str;
        int len=strlen(str);
        a=0;
        b=0;
        c=0;
        d=0;
        for(int i=0;i<len;i++)
		{
			if(str[i]=='L')
				a++;
			if(str[i]=='R')
				b++;
			if(str[i]=='U')
				c++;
			if(str[i]=='D')
				d++;
		}
		ans=min(a,b);
		cnt=min(c,d);
		sum=2*ans+2*cnt;
		if(ans&&cnt)
        {
            cout<<sum<<endl;
            for(i=1;i<=ans;i++) cout<<"L";
            for(i=1;i<=cnt;i++) cout<<"U";
            for(i=1;i<=ans;i++) cout<<"R";
            for(i=1;i<=cnt;i++) cout<<"D";
            cout<<endl;
        }
        else
        {
            if(ans) cout<<"2"<<endl<<"LR"<<endl;
            else if(cnt) cout<<"2"<<endl<<"UD"<<endl;
            else cout<<0<<endl;
        }
    }
}

每日小结:

今天的比赛做了两道题目在规定的时间,题目都过了一遍,但是有的只是单纯的看懂题目的要求而已,但是不知道如何去实现,在这次的补提中发现又很多的dp的元素,但是我这一部分好像学的还是不是太好,还要再巩固巩固,还有就是对于简单的题目可以尽快的做出和简单不要绕弯路了。
🆗✔,最后祝福明天高考的同学们做到都对,蒙的也都对,做个好梦,加油!💪

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值