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;
}