注:只看了1005&&1007,个人水平比较low,
乍看一眼,有点像前几天水的一道数论水题,说求一个数(2*10^9)的每位数之和,然后与此题无关系,其实题目就是不断求各位数的和然后补充上去,执行t次后判断得到的数时候能被11整除,很明显是有规律的,此数已经十几万位的数,不能直接%11,所以就会发现其实被11整除的数(只需判断奇数位的和与偶数位的和之差 %11==0 即可),然后然后就模拟,暴力求奇数位和偶数位的和~
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 10000010
using namespace std;
char num[N];
int a[15];
int main(){
int n,t,T=1;
while(scanf("%d%d",&n,&t)!=EOF){
if(n==-1&&t==-1) break;
int k=1,t1=0,t2=0;
int tmp=0;
for(int i=0;i<=t;i++){
int f=0;
while(n){
tmp+=n%10;
a[f++]=n%10;
n/=10;
}
for(int j=f-1;j>=0;j--){
if(k&1) t1+=a[j];
else t2+=a[j];
k++;
}
//cout<<tmp<<endl;
// cout<<t1<<" "<<t2<<endl;
n=tmp;
}
if((t1-t2)%11==0) printf("Case #%d: Yes\n",T++);
else printf("Case #%d: No\n",T++);
}
return 0;
}
啊~!DP[N][2],可惜一开始没想到还得需要一个vis[N][2]用来标记该位置是否可能存在1或0。。题目中加所谓point的条件就是某位与前一位不同时为1或0。。DP方程的话直接看代码吧。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define N 200010
int dp[N][2],num[N];
bool vis[N][2];
char str[N];
int main(){
int T;
scanf("%d",&T);
for(int k=1;k<=T;k++){
scanf("%s",str+1);
int n=strlen(str+1);
for(int i=1;i<=n;i++) scanf("%d",&num[i]);
memset(dp,0,sizeof(dp));
memset(vis,false,sizeof(vis));
vis[0][0]=true;
for(int i=1;i<=n;i++){
if(str[i]=='0') vis[i][0]=true;
else if(str[i]=='1') vis[i][1]=true;
else vis[i][0]=vis[i][1]=true;
}
for(int i=1;i<=n;i++){
if(str[i]=='?'){
if(vis[i-1][1]) dp[i][0]=max(dp[i-1][1]+num[i],dp[i][0]);
if(vis[i-1][0]) dp[i][0]=max(dp[i-1][0],dp[i][0]);
if(vis[i-1][0]) dp[i][1]=max(dp[i-1][0]+num[i],dp[i][1]);
if(vis[i-1][1]) dp[i][1]=max(dp[i-1][1],dp[i][1]);
}else if(str[i]=='0'){
if(vis[i-1][1]) dp[i][0]=max(dp[i-1][1]+num[i],dp[i][0]);
if(vis[i-1][0]) dp[i][0]=max(dp[i-1][0],dp[i][0]);
}else{
if(vis[i-1][0]) dp[i][1]=max(dp[i-1][0]+num[i],dp[i][1]);
if(vis[i-1][1]) dp[i][1]=max(dp[i-1][1],dp[i][1]);
}
}
printf("Case #%d: %d\n",k,max(dp[n][0],dp[n][1]));
}
return 0;
}