时间限制: 1 Sec 内存限制: 128 MB
题目描述:
小三的三分球总是很准的,但对于数学问题就完全没有想法了。他希望你来帮他解决下面的这个问题:
对于给定的n,从1!、2!、3!、…、n!中至少删去几个数,才可以使剩下的数的乘积为完全平方数?
输入:
仅一行,包含一个整数n(1≤n≤500)。
输出:
第一行包含一个整数k,表示最少需要删去的数字个数。
接下来一行,从小到大排列的k个[1,n]之间的整数,给出删数的方案。如果方案不止一种,输出方案从小到大排序序列最小的一组即可。
思路:
刚开始想了一个假算法,就是根据对4取余来算
如果 n%4 == 0 就删去 (n/2)!
如果 n%2 == 0 就删去一个 2!和一个 (n/2)!
…
详细思路见代码1
这个思路只有64分 因为这个代码只有保证可行却没有保证是最优解
因为这个思路不知道怎么处理删掉的那些数产生的化学反应,也没办法保证不会存在另外几个数产生化学反应后得到的结果不会比当前所得解更优
例如 对于n=18
这个思路会输出 删掉 2! 和 9! , 然后发现2! * 9! = 7! * 16 * 9
所以n=18 时正解应该是 输出 7!
正解:
虽然上面代码不能保证最优解,但我们也已经根据上面代码发现了最坏的情况也就是输出三个数,所以对于每一个n的最坏情况就是输出三个数
所以我们可以暴力枚举(i) , (i,j) , (i,j,k) 来寻找最优解
实现过程很巧妙
我也不知道这叫什么方法 分组hash?
也没心情写。。。
qaq
不过这里真的很精华。。。
具体思路看代码2吧
代码1:
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+15;
typedef long long ll;
int main()
{
ll n;
cin>>n;
if(n==1)
{
cout<<"0"<<endl;
cout<<endl;
return 0;
}
if(n%4==0)
{
cout<<"1"<<endl;
cout<<(n/2)<<endl;
return 0;
}
if(n%2==0)
{
if(n==2)
{
cout<<"1"<<endl;
cout<<"2"<<endl;
return 0;
}
cout<<"2"<<endl;
cout<<"2 "<<(n/2)<<endl;
}
if(n%4==1)
{
cout<<"2"<<endl;
cout<<(n/2)<<" "<<n<<endl;
return 0;
}
if(n%4==3)
{
if(n==3)
{
cout<<"2"<<endl;
cout<<"2 3"<<endl;
return 0;
}
cout<<"3"<<endl;
cout<<"2 "<<(n/2)<<" "<<n<<endl;
return 0;
}
return 0;
}
代码2:
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+15;
typedef long long ll;
bool vis[N];
ll prime[N],p[N],mp[N][2];
ll cnt=0;
void Prime()
{
int n=500;
vis[1]=1;
for(int i=2;i<=n;i++)
{
if(!vis[i])
prime[++cnt]=i;
for(int j=1;j<=cnt&&i*prime[j]<=n;j++)
{
vis[i*prime[j]]=1;
if(i%prime[j]==0)
break;
}
}
// cout<<cnt<<endl;
}
int main()
{
Prime();
ll n;
p[0]=1;
for(int i=1;i<=50;i++)
{
p[i]=p[i-1]*2;
}
cin>>n;
for(int i=2;i<=n;i++)
{
ll x=i;
for(int j=1;j<=50;j++)
{
int op=0;
while(x%prime[j]==0)
{
op++;
x/=prime[j];
}
if(op%2==1)
{
mp[i][0]^=p[j];
}
}
for(int j=51;j<=95;j++)
{
int op=0;
while(x%prime[j]==0)
{
op++;
x/=prime[j];
}
if(op%2==1)
{
mp[i][1]^=p[(j-50)];
}
}
mp[i][0]^=mp[i-1][0];
mp[i][1]^=mp[i-1][1];
}
ll ans0=0,ans1=0;
for(int i=2;i<=n;i++)
{
ans0^=mp[i][0]; ans1^=mp[i][1];
}
// cout<<ans0<<" "<<ans1<<endl;
for(int i=2;i<=n;i++)
{
if(mp[i][0]==ans0&&mp[i][1]==ans1)
{
cout<<"1"<<endl;
cout<<i<<endl; return 0;
}
}
for(int i=2;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
if( (mp[i][0]^mp[j][0])==ans0 && (mp[i][1]^mp[j][1])==ans1 )
{
cout<<"2"<<endl;
cout<<i<<" "<<j<<endl; return 0;
}
}
}
for(int i=2;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
for(int k=j+1;k<=n;k++)
{
if( (mp[i][0]^mp[j][0]^mp[k][0])==ans0 && (mp[i][1]^mp[j][1]^mp[k][1])==ans1 )
{
cout<<"3"<<endl;
cout<<i<<" "<<j<<" "<<k<<endl; return 0;
}
}
}
}
return 0;
}