题目地址:
http://acm.sgu.ru/submit.php?problem=169
http://acm.sgu.ru/submit.php?problem=178
169解析:因为n和n+1相邻,因此两者的P(n)必然也相邻,且为一位数,则要求n的前导必然为1,只有最后一位可以变动,现在讨论最后一位。(结尾为1、2、5的时候,p(n)显然满足,作为已知)为1的时候必然成立,为2的时候只有当尾数为3的数整除3,则要求前面1的个数是3的倍数。为5的时候成立则要求为6的数整除6,测试发现前导有3的倍数个1的时候一直为1、5、3循环,则36必然整除6.(要求前导有3个倍数个1)。当6成立的时候,则要求尾数为7可以整除7,测试发现前导有6个倍数个1的时候为1、4、6、5、2、0,显然最后一位的7可以整除7,因此当6成立的时候前导有6个倍数个1.(不得不感叹数字真的太奇妙了)
#include <iostream>
#include <cmath>
#include <string>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <algorithm>
#include <cstdio>
using namespace std;
typedef long long ll;
#define INF 0xfffffff
#define MAX(a,b) a>b?a:b
#define MIN(a,b) a>b?b:a
int main()
{
int i,j,k,t;
int m,n;
while(cin>>k)
{
if(k==1) cout<<"8"<<endl;
else if((k-1)%3) cout<<"1"<<endl;
else
{
if((k-1)%2==0) cout<<"4"<<endl;
else cout<<"3"<<endl;
}
}
return 0;
}
178解析:破坏X个会产生至少X个1,会产生X+1~2X+1块,显然产生的块数越大,所组成的可能性越大,破坏X个达到的范围也就越大。因此直接考虑产生2X+1块(包括已有的X个1)的情况。X个1能组成1~X中间的任意数,这是显然,因此需要在X+1处有个值,(不然不满足条件),则加上X+1这个值之后显然可以组成X+1~2X+1之间的值,则需要在2X+2处有个值,可以组成2X+2~2(2X+2)-1之间的值,依次类推,最后在后面加上X+1个数,则表示的区间为X*2^X(这个又是上个(X-1)表示的最大值加1)到(X+1)*2^(X+1)-1.
#include <iostream>
#include <cmath>
#include <string>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <algorithm>
#include <cstdio>
using namespace std;
typedef long long ll;
#define INF ((ll)1<<59)
#define MAX(a,b) a>b?a:b
#define MIN(a,b) a>b?b:a
#define M 50
struct N
{
ll st,ed; //记录必须破坏x个的开始N值,以及破坏x个达到的最大的值。
}a[M];
ll f[M];
void init()
{
a[1].st=1;
int j;
for(int i=1;i<M-1;i++)
{
f[0]=i+1;
for(j=1;j<=i;j++)
{
ll temp=f[j-1]*2;
if(temp>INF) break;//大于要求的值之后直接跳出。
else f[j]=temp;
}
a[i].ed=2*f[j-1]-1;
a[i+1].st=a[i].ed+1;
}
}
int search(ll n) //查找在那个区间里。
{
for(int i=1;i<M;i++)
if(n>=a[i].st&&n<=a[i].ed) return i;
}
int main()
{
int i,j,k,t;
ll m,n;
init();
while(cin>>n)
{
if(n==1) cout<<"0"<<endl;
else cout<<search(n)<<endl;
}
return 0;
}