您的位置:首页 > 其它

codeforeces 792 C. Divide by Three (dp || 贪心)

2017-03-28 21:57 501 查看
题意:

一个1e5长度的数字,去掉几个数字后让它是三的倍数,要求去掉的数最少,而且要去掉前导零

解题思路:

一开始瞎贪心,面向数据编程后终于搞出来了。

其实总结起来只要注意五种情况

1.sum%3==0,直接输出就行

2.sum%3==1.去掉一个1。

3.sum%3==1.去掉两个2.2

4.sum%3==2.去掉一个2.

5.sum%3==2.去掉两个1

对于sum%3==1的两种子情况,我们可以都处理一遍,然后看那个留下了的串长,就保留哪个,但是我们在删除数的时候一定要从后往前跑,因为从前面开始删可能会删除一个数后都是前导零,导致要删除的数增多。

sum%3==2相同。

还有dp的做法,是祥巨教我的,就不用考虑这么多情况了,不容出错,但对于我这种弱鸡来说还是写了很久。

开出dp[i][j][k],表示到i个数,对3取模是j,需要取多少个数,k=1表示高位已经取值,可以去零,k=0表示高位还没取值,出现的零都是前导零,不可取。

dp一开始初始化为-1,表示当前状态不可到达。

转移的时候:

对于k=1的情况

dp[i][(j)%3][k]=dp[i-1][j][k];

dp[i][(j*10+str[i]-'0')%3][k]=dp[i-1][j][k]+1;

对于k=0的情况

当str[i]=='0'时,不要取,但是我们可以更新j=0的dp,将其设为0(原本是-1表示不可达到)

当str[i]!=‘0’时:

dp[i][(j)%3][k]=dp[i-1][j][k];

dp[i][(j*10+str[i]-'0')%3][1]=dp[i-1][j][k]+1;

贪心的代码:

#include <bits/stdc++.h>

using namespace std;
const int maxn=1e5+5;
char a[maxn];
int b[maxn];
char ans[maxn];
int check()
{
int res=0, i=0;

for(; a[i] ; i++)if(b[i]!=-1)if(a[i]!='0')break;
for(; a[i]; i++)if(b[i]!=-1)res++;
if(res==0)res=1;
return res;
}
int main()
{
return 0*printf("%lld\n", 0xcf);
scanf("%s", a);
int i, j, k;
int sum=0;
for(i=0; a[i]; i++)sum+=a[i]-'0';
for(i=0; a[i]; i++)b[i]=(a[i]-'0')%3;
sum%=3;
if(sum==0)
{
for(i=0; a[i] && a[i]=='0'; i++);
if(!a[i])printf("0\n");
else for(; a[i]; i++)printf("%c", a[i]);
return 0;
}
else if(sum==1)
{
int l1=0, l2=0, x;
int len=strlen(a);
for(i=len-1; i>=0; i--)if(b[i]==1){b[i]=-1;break;}
if(i>=0)
{
l1=check();
b[i]=1;
}
j=0;

for( k=len-1; k>=0; k--)
{
if(b[k]==2)
{

b[k]=-1;
j++;
if(j==2)break;
x=k;
}
}
if(k>=0)
{
l2=check();
}
//           cout<<l1<<" "<<l2<<endl;
if(l2<l1)
{
//     cout<<x<<" "<<k<<" "<<j<<endl;
if(j==2)b[k]=b[x]=1, b[i]=-1;
else if(j==1)b[i]=-1, b[x]=1;
else if(j==0)b[i]=-1;
}

}
else if(sum==2)
{
int len=strlen(a);
int x, flag=0, l1=0, l2=0;
for(i=len-1; i>=0; i--)
{
if(b[i]==2)
{
b[i]=-1;
break;
}
}
if(i>=0)
{
l1=check();
b[i]=2;
}
j=0;

for( k=len-1; k>=0; k--)
{
if(b[k]==1)
{

b[k]=-1;
j++;
if(j==2)break;
x=k;
}
}
if(k>=0)
{
l2=check();
}
//      cout<<l1<<" "<<l2<<endl;
if(l2<l1)
{
//     cout<<x<<" "<<k<<" "<<j<<endl;
if(j==2)b[k]=b[x]=1, b[i]=-1;
else if(j==1)b[i]=-1, b[x]=1;
else if(j==0)b[i]=-1;
}

}
j=0;
for(i=0; a[i]; i++)if(b[i]!=-1)ans[j++]=a[i];
ans[j]='\0';
//    printf("%s\n", ans);
for(i=0; ans[i] && ans[i]=='0'; i++);
if(!ans[i])
{
if(i==0)return 0*printf("-1\n");
else return 0*printf("0\n");
}
for(; ans[i]; i++)printf("%c", ans[i]);
return 0;
}


 dp的代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int dp[maxn][3][2];
struct p
{
int x;
int y;
}pre[maxn][3][2];
char a[maxn];
char ans[maxn];
int main()
{
scanf("%s", a+1);
int i, j, k, n, x;
n=strlen(a+1);
memset(dp, -1, sizeof(dp));
dp[0][0][0]=0; //第i个数,sum%3==0,k=0的状态是可能的
for(i=1; i<=n; i++)
{
x=a[i]-'0';
for(j=0; j<3; j++)
{
for(k=0; k<2; k++)
{
if(k==0)
{
if(x==0)
{
if(j==0)dp[i][j][k]=0;
}
else
{
if(dp[i][(j*10)%3][k]<dp[i-1][j][k])
{
dp[i][(j*10)%3][k]=dp[i-1][j][k];
pre[i][((j*10))%3][k].x=j;
pre[i][((j*10))%3][k].y=k;
}
if(dp[i][((j*10)+x)%3][1]<dp[i-1][j][k]+1 && dp[i-1][j][k]!=-1) //当前驱状态是可能的时候才转移
{
pre[i][((j*10)+x)%3][1].x=j;
pre[i][((j*10)+x)%3][1].y=k;

dp[i][((j*10)+x)%3][1]=dp[i-1][j][k]+1;
//   printf("%d %d %d %d %d %d\n", i, (j*10+x)%3, j, k, dp[i][(j*10+x)%3][1], dp[i-1][j][k]);
}
}
}
else
{
if(dp[i][(j*10)%3][k]<dp[i-1][j][k])
{
dp[i][(j*10)%3][k]=dp[i-1][j][k];
pre[i][((j*10))%3][1].x=j;
pre[i][((j*10))%3][1].y=k;

}
if(dp[i][((j*10)+x)%3][1]<dp[i-1][j][k]+1 && dp[i-1][j][k]!=-1)
{
pre[i][((j*10)+x)%3][1].x=j;
pre[i][((j*10)+x)%3][1].y=k;

dp[i][((j*10)+x)%3][1]=dp[i-1][j][k]+1;
}
}
//                printf("%d %d %d dp%d pre%d\n", i, j, k, dp[i][j][k], pre[i][j][k].x);
}
}
}
if(dp
[0][1]==-1)//在不产生前导零的情况下找不到这样一个数
{
for(i=1; i<=n; i++)if(a[i]=='0')break;
if(i<=n)printf("0\n");
else printf("-1\n");
}
int y, top=0;
int nx, ny;
nx=0;
ny=1;
for(i=n; i>=1; i--)
{
x=pre[i][nx][ny].x;
y=pre[i][nx][ny].y;
if(dp[i-1][x][y]<dp[i][nx][ny])ans[top++]=a[i];
nx=x;
ny=y;
}
for(i=top-1; i>=0; i--)printf("%c", ans[i]);
}


    
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: