既然蓝桥杯过了,从今日起恢复每日打卡。
传送门:点击打开链接
每日打卡(1/1)
题目大意:
给你一个正整数(1-2e9),要求出至少删去其中几个数字,才能让它变成一个完全平方数。
思路一
也是我想的思路,对于数n的每一位,我们都有删或者不删两种操作,也就是说,至多求2^9次后,我们就能得到结果。
而如何枚举成了我的另一个问题,之前写的dfs一直出错。
所以,还是参考了以前写的一篇文章的枚举法。
for(int i=0;i<(1<<len);i++)
dfs(i,s);
for(int j=0;j<len;j++)
{
if((k>>j)&1)
{
del(j);
}
}
这样一来,就枚举完成了所有的情况。
这时候我们可以依次选择删或者不删,删完后再判断是否是平方数。
在第一次的写法中,我将字符串s中删去的值记为0,,结果WA了。这显然是不可取的,举个栗子,输入n=101,正确结果为2,可是输出的全是1,原因就是将删去的末位1记为了0,导致错误。。
而将这个bug修复后,又出现了新的错误,在上述例子中,输出的依然是1。仔细思考后发现,如果删去百位上的1,那么原数就记为了 01 ,依然属于合法的。
因此,做了第二个改进,将数字首位的0全部去掉。。
while(1)
{
if(q.front()==0)
q.pop();
else
break;
}
然后又RE了,原来是如果输入0(还有其他例子),它就会死循环。。。
因此,再循环条件中加上 !q.empty()。
最后,我们得到了AC解法
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5;
const int inf = 0x3f3f3f3f;
string s;
int len,ans,tot,a[maxn];
bool check(string s)
{
queue<int> q;
int n = s.length();
for(int i=0;i<n;i++)
{
if(s[i]!='*')
q.push(s[i]-'0');
}
while(1&&!q.empty())
{
if(q.front()==0)
q.pop();
else
break;
}
tot = len-q.size();
if(!q.empty()) {
int x = q.front();
q.pop();
while(!q.empty())
{
x = x*10+q.front();
q.pop();
}
int temp = sqrt(x);
if(temp*temp==x)
{
// cout<<x<<endl;
return true;
}
}
return false;
}
void del(int x)
{
a[x] = !a[x];
}
void dfs(int k,string s)
{
// cout<<k<<endl;
memset(a,0,sizeof(a));
tot = 0;
for(int j=0;j<len;j++)
{
if((k>>j)&1)
{
del(j);
}
}
for(int i=0;i<len; i++)
{
if(a[i])
{
s[i] = '*';
}
}
// cout<<s<<endl;
if(check(s)) {
ans = min(ans,tot);
}
}
int main()
{
cin>>s;
len = s.length();
// cout<<len<<endl;
ans = inf;
for(int i=0;i<(1<<len);i++)
dfs(i,s);
if(ans==inf) {
cout<<-1<<endl;
return 0;
}
cout<<ans<<endl;
return 0;
}
思路二
在CSDN上看到有一位仁兄提供了一个思路。
就是枚举1-n范围内的所有完全平方数,然后将每一个数于n相比,比较它们相同的位数,尽量取大的。
很显然,最终结果就是 n的长度-相同位数长度最大值。