暑假专题tes02

A题链接;https://hihocoder.com/problemset/problem/1326

题意:输入一个数N;代表有N个字符串(每个字符串只存在0和1),您有两种操作,0变1,1变0;要使所有的0只能存在于1前面;求最少操作次数;

PS:所有的0都只能在1前面;所有最后满足答案的状态即可,枚举所有分界点的位置i,i前面都是0,i后面全是1,总共只可能有len种可能,随你的分界点从哪,都只有len种位置分界(len为字符串长度),故可以建立一个数组记录前缀,即此前面有多少0,前面有多少1;最后选取最少的即为答案;

#include <iostream>
#include<stdio.h>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1005;
char s[N];
int dp[N][2];
int main()
{
    int n;
    cin>>n;
    while(n--){
        cin>>s;
        int len=strlen(s);
        for(int i=0;i<len;i++)     
            dp[i][0]=0,dp[i][1]=0;

        if(s[0]=='0')             //初始化 
            dp[0][0]=1,dp[0][1]=0;
        else    dp[0][1]=1,dp[0][0]=0;

        for(int i=1;i<len;i++){     //求第i个位置前有多少个0和1; 
            if(s[i]=='0'){
                dp[i][0]=dp[i-1][0]+1;
                dp[i][1]=dp[i-1][1];
            }
            else{
                dp[i][1]=dp[i-1][1]+1;
                dp[i][0]=dp[i-1][0];
            }
        }

        int ans=999999;
        for(int i=0;i<len;i++){   //以第i个位置为分界线,求需要变的次数(将i前面的1全部变为0和将i后面的0全部变为1的次数) 
            if(s[i]=='1')
            ans=min(ans,dp[i-1][1]+dp[len-1][0]-dp[i][0]);
            else
            ans=min(ans,dp[i][1]+dp[len-1][0]-dp[i][0]);
        }
        cout << ans << endl;
    }

    return 0;
}

当然,这种做法,太繁琐了,有点蠢;正解还是DP;

也就是说,第i个位置,如果为0,则前面全部都要是0,如果为1,则前面要么全是1,要么全是0;

DP方程见代码;

#include <iostream>
#include<stdio.h>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1005;
char s[N];
int dp[N][2];//0代表当前为0时,1代表当前为1时 
int main()
{
    int n;
    cin>>n;
    while(n--){
        cin>>s;
        int len=strlen(s);
        memset(dp,0,sizeof(dp)); //初始化 
		if(s[0]=='0')
			dp[0][1]=1,dp[0][0]=0;
		else
		dp[0][0]=1,dp[0][1]=0;
		
		for(int i=1;i<len;i++){  
			if(s[i]=='0'){           //如果当前为0,则dp[i][0]就为我前面0的个数 
				dp[i][0]=dp[i-1][0];
				dp[i][1]=dp[i-1][1]+1;//dp[i][1]则是当前为1满足条件的最小值,加上把第i位置0转化为1的操作 
			}
			else{
				dp[i][1]=min(dp[i-1][0],dp[i-1][1]); //维护 一个最小值 
				dp[i][0]=dp[i-1][0]+1;//若将此位变为0,则前面必须全部为0,加上此操作; 
			}
		}
        cout <<min(dp[len-1][0],dp[len-1][1])<< endl;
    }

    return 0;
}

故此DP就是将 所有的 第i位置,为0还是为1满足条件的状态,递推;

C题:http://codeforces.com/problemset/problem/1196/D1

题意:给你一个字符串s的长度,输入字符串,并要求你找到一个长度为K的s的子串是RGB循环串的子串,求更改S的最少次数;

ps:此题巧妙在建立一个数组'R''G''B',就可以了,之后,全在此数组循环即可,创建一个数组sum代表前缀;sum[0],sum[1]

sum[2]代表从rgb循环gbr循环和brg循环的三种循环模式前缀;sum与s不相等时,sum+1;求出S串所有的要改变的次数;最后取最小值即可

    #include <iostream>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int N = 2e5+10;
    int sum[3][N];
    char c[3]={'R','G','B'};
    int main()
    {
        int _;
        cin>>_;
        while(_--){
            int n,k;
            char s[N];
            cin>>n>>k;
            scanf("%s",s+1);
            for(int i=0;i<=n;i++){
                sum[0][i]=0;sum[2][i]=0;sum[1][i]=0;
            }
     
            for(int i=1;i<=n;i++){
                for(int j=0;j<3;j++){
                    if(s[i]!=c[(i+j-1)%3])    //代表从j开始的循环串,到第i位需要更改的次数; 
                        sum[j][i]=sum[j][i-1]+1;
                    else
                        sum[j][i]=sum[j][i-1];
                }
            }
            int ans=N;
     
            for(int i=0;i<=n-k;i++)
                ans=min(min(sum[0][i+k]-sum[0][i],sum[1][i+k]-sum[1][i]),min(ans,sum[2][i+k]-sum[2][i]));
            cout << ans << endl;
        }
     
        return 0;
    }

E题:一个树形DP,本蒟蒻不熟,等以后熟悉再K;上个链接:http://codeforces.com/problemset/problem/1153/D

F题:http://codeforces.com/problemset/problem/455/A

题意:一个无聊的人玩的无聊的游戏,输入n,即为N个数, 如果你要取得分数ai,则ai-1和ai+1的分数就都得不到了;

ps:此题是为DP;即dp[i]表示取 ai和不取ai分数的值。DP方程,dp[i]为取a[i]则i-1不能取,方程为dp[i-2]+a[i],否则dp[i]=dp[i-1];

    #include<iostream>
    #include<stdio.h>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    typedef long long int ll;
    const int N = 1e5+10;
    ll b[N];
    ll dp[N];
    int main()
    {
    	std::ios::sync_with_stdio(false);
    	cin.tie(0);
    	int minn=N,maxx=-N;
    	//cout<<N<<endl;
    	int n,temp;
    	cin>>n;
    	
    	for(int i=1;i<=n;i++){//将最小值和分数记录下来 
    		cin>>temp;
    		b[temp]+=temp;
    		minn=min(minn,temp);
    		maxx=max(maxx,temp);
    	}
    	
    	
    	for(int i=minn;i<=maxx;i++){  //从能取的最小值到最大值 递推 
    		dp[i]=max(dp[i-1],dp[i-2]+b[i]);
    	}
    	
    	cout<<dp[maxx]<<endl;
    	
    }
发布了97 篇原创文章 · 获赞 3 · 访问量 9446

猜你喜欢

转载自blog.csdn.net/foolishpichao/article/details/97648755
tes
今日推荐