SRM607 题解(除T3外)

T1:

题目大意:给一个串(字符集为:'a'..'z','?'),'?'代表'a'..'z'中等概率选择一个字母,问原串中期望回文子串个数。

主要思路:简单题,枚举每个子串,然后算出成为回文串的概率。


#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<string>
using namespace std;

string S;

double calc(int l,int r,int n){
	double ans=1,ans1=0;
	while (l-1>=0 && r+1<n){
		if (S[l-1]!=S[r+1])
			if (S[l-1]!='?' && S[r+1]!='?') return ans1;
		if ((S[l-1]=='?' || S[r+1]=='?') && l-1!=r+1)
			ans=ans/26;
		ans1=ans1+ans;
		--l;
		++r;
	}
	return ans1;
}

class PalindromicSubstringsDiv1{
public:
	double expectedPalindromes(vector <string> S1, vector <string> S2){
		S="";
		int n=S1.size();
		for (int i=0; i<n; ++i) S+=S1[i];
		n=S2.size();
		for (int i=0; i<n; ++i) S+=S2[i];
		double ans=0;
		n=S.size();
		for (int i=0; i<n; ++i){
			ans+=calc(i+1,i-1,n);
			ans+=calc(i+1,i,n);
		}
		return ans;
	}
};



T2:

题目大意:给出两个数字串,每次可以将第一个的其中连续一段加一或者减一(注意,是循环的,即9+1=0),问最少对第一个串操作多少次才能变成第二个串。


主要思路:对于 第一个串s1[1..n]和 第二个串s2[1..n] ,对它们做差得到s3[1..n](只有0..9),s3[1..n]代表的既是对s3[1..n]操作把它变成全是0。对s3[1..n]做差得到s4[1..n](s4[i]=s3[i]-s3[i-1]),,显然将s3变为0就是将s4变成0,而且操作s3的区间操作就是对s4的两个不同位置的数进行操作(s4[i]+=d,s4[j]-=d),而且s4可以对任意一个数加一个任意数(但是相应的就要在其他某个数减去相应的数值),于是原问题变成 对s4的某些数增加一些值,增加的总和为D ,对s4得另一些数减去一些值,总和为-D,这样我们就可以dp了。

f[i][j]:代表前i个数字全变成0,且总共增加了j的最小代价。

最后f[n+1][0]就是答案

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<vector>
using namespace std;

const int MAXN=2510;
string S1,S2;
int num[MAXN],sum[MAXN];
int a1[MAXN],a2[MAXN];
int f[40000],g[40000];
const int ZERO=20000;

class CombinationLockDiv1{
public:
	int minimumMoves(vector <string> P, vector <string> Q){
		int n=P.size();
		S1="";
		for (int i=0; i<n; ++i) S1+=P[i];
		n=Q.size();
		S2="";
		for (int i=0; i<n; ++i) S2+=Q[i];
		n=S1.size();
		for (int i=0; i<n; ++i) num[i]=S1[i]-S2[i];
		for (int i=1; i<=n; ++i) sum[i]=num[i]-num[i-1];
		sum[0]=num[0];
		if (n==0) return 0;
		for (int i=0; i<=n; ++i){
			while (sum[i]<0) sum[i]+=10;
			while (sum[i]>10) sum[i]-=10;
			a1[i]=10-sum[i];
			a2[i]=sum[i];
		}
		memset(f,63,sizeof(f));
		f[ZERO-a1[0]]=a1[0];
		f[ZERO+a2[0]]=a2[0];
		for (int i=0; i<n; ++i){
			memset(g,63,sizeof(g));
			for (int j=0; j<40000; ++j){
				if (j-a1[i+1]>=0) g[j-a1[i+1]]=min(g[j-a1[i+1]],f[j]+a1[i+1]);
				if (j+a2[i+1]<40000) g[j+a2[i+1]]=min(g[j+a2[i+1]],f[j]+a2[i+1]);
			}
			memcpy(f,g,sizeof(f));
		}
		//for (int i=0; i<=n; ++i) printf("%d %d\n",a1[i],a2[i]);
		return f[ZERO]/2;
	}
};



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值