题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6020点击打开链接
MG loves apple
Time Limit: 3000/1500 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 988 Accepted Submission(s): 188
A valid number does not contain a leading zero, and these apples have just made a valid N digit number.
MG has the right to take away K apples in the sequence, he wonders if there exists a solution: After exactly taking away K apples, the valid N−K digit number of remaining apples mod 3 is zero.
MG thought it very easy and he had himself disdained to take the job. As a bystander, could you please help settle the problem and calculate the answer?
And as for each case, there are 2 integer N(1<=N<=100000) , K(0<=K < N) in the first line which indicate apple-number, and the number of apple you should take away.
MG also promises the sum of N will not exceed 1000000 。
Then there are N integers X in the next line, the i-th integer means the i-th gold’s value( 0<=X<=9 ).
If the solution exists, print”yes”,else print “no”.(Excluding quotation marks)
2 5 2 11230 4 2 1000
yes no
题意:给你个小于100000位的n位数 然后让你在任意位上抽去k个数 问能否形成一个能被3整除的数
小学老师告诉我们 当一个数的各个位相加能%3==0时 这个数就能%3==0
因此我们对这个大数上的数位进行考虑
我们统计所有的数位上的数x 将他分成四类
1. 为0的数
2. x%3==1的数
3.x%3==2的数
4.x%3==0且不为0的数
我们cnt0表示情况1的个数
cnt1表示情况2的个数
cnt2表示情况3的个数
cnt3表示情况4的个数
我们观察这四类数的特点 发现有如下规律
1.cnt0+cnt1+cnt2+cnt3==n
2.当一个数能被3整除时 必有
abs(cnt1-cnt2)%3==0
(xjb乱证明:因为当一个数能被3整除时
有:(0*cnt0+1*cnt1+2*cnt2+3*cnt3)%3==0
而其中(0*cnt0+3*cnt3)%3==0
因此(1*cnt1+2*cnt2)%3==0-----@
而又因为(1+2)%3==0 (2+2+2)%3==0 (1+1+1)%3==0
因此必定能将@式中的1*cnt1+2*cnt2拆成
a*(1+2)+b*(2+2+2)+c*(1+1+1)---#
的形式 其中a b c为整数
将#式化简 得形式:
(1*cnt1+2*cnt2)=(a+3c)*1+(a+3b)*2
而cnt1=a+3c cnt2=a+3b
即abs(cnt1-cnt2)%3==0
)
接下来是模拟操作
我们枚举要删除的第一四种情况的num0的个数(因为他们都是%3==0)和第二种情况num1的个数 从而确定num2的个数
然后根据规律判断剩余的数是否存在组成满足题意的情况
一开始觉得枚举会超时的 但是看博客后知道不会超时。。。
因为题目要求不能有前导0 因此对其进行贪心操作:
对于第二种和第三种情况 我们从后往前删
对于第一种和第四种情况 我们先删第一种 再删第四种 并且删第一种从前往后 第四种从后往前
判断是否成立时 除了判断满足规律二以外 还要注意前导0的情况
即2 3 4种情况的最前位的数的位置是否在最前位的0的位置之前 若有 则符合条件
然后其实对于贪心操作的时候并没有那么麻烦
用数组记录2 3 4种情况出现的个数 如果被删完则把他的位置置无穷大 如果没有则取第一个数的位置进行判断
题目要求如果能够只删的剩下一个0 也算yes 因此加特判
思考模拟过程很磨时间 需要感受其间各个数的表示与联系
另外除了附代码以外 给自己写的测试数据
(代码中cnt与num意义与题解中相反)
#include <bits/stdc++.h>
using namespace std;
int main()
{
int t;
cin >> t;
while(t--)
{
string s;
int n,k;
cin >> n >> k;
cin >> s;
vector<int > s0,s1,s2,s3;
s1.push_back(1111111);
s2.push_back(1111111);
s3.push_back(1111111);
int num0=0,num1=0,num2=0,num3=0;
for(int i=0;i<n;i++)
{
if(s[i]=='0')
{
s0.push_back(i);
num0++;
}
else if((s[i]-'0')%3==0)
{
s3.push_back(i);
num3++;
}
else if((s[i]-'0')%3==1)
{
s1.push_back(i);
num1++;
}
else if((s[i]-'0')%3==2)
{
s2.push_back(i);
num2++;
}
}
if(n==k+1&&s0.size())
{
cout << "yes" << endl;
continue;
}
int flag=0;
for(int cnt0=0;cnt0<=(num0+num3)&&cnt0<=k;cnt0++)
{
for(int cnt1=0;cnt1<=num1&&cnt1<=k-cnt0;cnt1++)
{
int cnt2=k-cnt1-cnt0;
if(cnt2>num2)
continue;
int pos3=cnt0-num0;
int pos2=num2-cnt2;
int pos1=num1-cnt1;
if(pos2>0&&s2.size()>1)
pos2=1;
else
pos2=0;
if(pos1>0&&s1.size()>1)
pos1=1;
else
pos1=0;
if(pos3<0)
pos3=0;
pos3=num3-pos3;
if(pos3>0&&s3.size()>1)
pos3=1;
else
pos3=0;
if(abs((num2-cnt2)-(num1-cnt1))%3==0&&
(cnt0>=s0.size()||(s0[cnt0]>s1[pos1])||(s0[cnt0]>s2[pos2])||s0[cnt0]>s3[pos3]))
{
flag=1;
break;
}
}
}
if(flag)
cout << "yes" << endl;
else
cout << "no" << endl;
}
}
100 3 2 110 3 2 113 5 0 11200 5 1 11200 5 2 11200 5 3 11200 5 4 11200 5 2 11230 4 2 1000 1 0 3 4 3 1130 4 3 1120 4 3 1111 4 2 1111 4 2 1110 4 2 1210 4 0 1210 3 1 121 3 2 121 3 1 100 3 2 100 3 2 110 4 2 1310 4 2 1031 3 2 131 4 1 1303 6 2 100101
测试数据参考答案:
100 3 2 110 yes 3 2 113 yes 5 0 11200 no 5 1 11200 yes 5 2 11200 yes 5 3 11200 yes 5 4 11200 yes 5 2 11230 yes 4 2 1000 no 1 0 3 yes 4 3 1130 yes 4 3 1120 yes 4 3 1111 no 4 2 1111 no 4 2 1110 no 4 2 1210 yes 4 0 1210 no 3 1 121 yes 3 2 121 no 3 1 100 no 3 2 100 yes 3 2 110 yes 4 2 1310 yes 4 2 1031 no 3 2 131 yes 4 1 1303 yes 6 2 100101 yes