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;
贪心的代码:
dp的代码:
一个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]); }
相关文章推荐
- [CF792C] Divide by Three(dp,记录路径)
- Codeforces-792C:Divide by Three(DP)
- (2017/4、8、/ B - Divide by Three) CodeForces - 792C (dp)(暴力破解)
- Codeforces 792C Divide by Three【Dp+记录路径】
- Educational Codeforces Round 18 -- C. Divide by Three (贪心)
- BZOJ3037 创世纪 [贪心][树形DP]
- hdu5236 Article(贪心+概率dp)
- luogu1970【2013提高】花匠(DP/贪心)
- 第八届山东省赛 sdut 3903 CF(贪心+dp)
- hdu 1257 最少拦截系统(简单dp+贪心)
- [HDOJ5773]The All-purpose Zero(贪心,DP)
- 蓝桥杯-导弹拦截-贪心-dp-java
- WUST OJ 1421 we love girl(贪心或DP)
- nyoj 106 背包问题 (dp或贪心都可)
- Yogurt factory(POJ 2393 贪心 or DP)
- 洛谷1417 烹调方案 dp 贪心
- HDU 1257 最少拦截系统(基础DP,贪心)
- 算法——硬币选择问题(dp、贪心)
- 51nod 1378 夹克老爷的愤怒[贪心][树形dp?]
- 【剩余类+贪心+DP】Codeforces571B[Minimization]题解