01:质数的和与积
-
描述
-
两个质数的和是S,它们的积最大是多少?
输入
- 一个不大于10000的正整数S,为两个质数的和。 输出
- 一个整数,为两个质数的最大乘积。数据保证有解。 样例输入
-
50
样例输出
-
589
来源
-
《奥数典型题举一反三(小学五年级)》 (ISBN 978-7-5445-2882-5) 第三章 第二讲 例1
这是一道小学数学题啊。。。
我的方法是先用线性筛素数打出一个素数表,然后就i从S/2开始,往下减少,如果i和(S-i)都是质数,那么输出他们的积,并且return 0;
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
bool tf[10010]={true,true};//素数表
int s;
int main()
{
for(int i=2;i<=100;i++)//线性筛素数,对于i<=sqrt(maxn),将i的每个倍数标记为合数
{
if(tf[i])continue;//如果i已经是合数,那么他的倍数肯定已经被标记过了,所以无需再次标记
for(int j=2;i*j<=10000;j++)tf[i*j]=true;//如果是质数,进行标记操作
}
scanf("%d",&s);
for(int i=s/2;i>=2;i--)if(!tf[i]&&!tf[s-i])//如果i和(s-i)都是质数
{
printf("%d\n",i*(s-i));
return 0;//输出并返回
}
}
-
求两个不超过200位的非负整数的积。
输入
- 有两行,每行是一个不超过200位的非负整数,没有多余的前导0。 输出
- 一行,即相乘后的结果。结果里不能有多余的前导0,即如果结果是342,那么就不能输出为0342。 样例输入
-
12345678900 98765432100
样例输出
-
1219326311126352690000
来源
- 程序设计实习2007
02:大整数乘法
-
描述
这题的数据有点水,不用FFT都可以过。。。但是我不会FFT
我写的代码是偏向于模板类型的(中了一点面向对象的毒),用了重载运算符
高精度的中心思想是通过类似于笔算的方法。比如说我们要计算200位+200位的加法,我们是从最低位(个位)开始,一步一步往上加,同时保存进位。
为了阅读和编写的方便,我没有用高精压位:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=410;
struct bigint
{
int l,num[maxn];//l是大整数的长度,num保存每一位,num[0]是个位,依此类推
bigint(){l=1;memset(num,0,sizeof num);}//初始化
void in(){char s[maxn];scanf("%s",s);l=strlen(s);for(int i=0;i<l;i++)num[i]=s[l-i-1]-'0';}//输入函数
void out(){for(int i=l-1;i>=0;i--)printf("%d",num[i]);printf("\n");}//输出函数,内置
bigint operator+(bigint a)//加法操作
{
bigint ans;
ans.l=max(l,a.l)+1;//更新长度
for(int i=0;i<ans.l;i++)ans.num[i]=num[i]+a.num[i];//计算每一位的值
for(int i=1;i<ans.l;i++)ans.num[i]+=ans.num[i-1]/10,ans.num[i-1]%=10;//计算进位
if(!ans.num[ans.l-1])ans.l--;//判断最高位是否是0
return ans;//返回
}
bigint move(int a)//移位操作,move(a)代表*(10^a)
{
bigint ans;
ans.l=l+a;
for(int i=0;i<l;i++)ans.num[i+a]=num[i];
return ans;
}
bigint operator*(int a)//乘法操作,乘以一个小于10的数
{
bigint ans;
ans.l=l+1;
for(int i=0;i<ans.l;i++)ans.num[i]=num[i]*a;//计算
for(int i=1;i<ans.l;i++)ans.num[i]+=ans.num[i-1]/10,ans.num[i-1]%=10;//进位
if(!ans.num[ans.l-1])ans.l--;//判断最高位是否为0
return ans;//返回
}
bigint operator*(bigint a)//乘法,乘以一个大整数
{
bigint ans;
ans.l=l+a.l+1;//更新长度
for(int i=0;i<l;i++)ans=ans+(a*num[i]).move(i);//对于每一位,加上乘以这一位的值
while(ans.l!=1&&!ans.num[ans.l-1])ans.l--;//判断是否需要更新总长度
return ans;//返回
}
}a,b;
int main()
{
a.in();b.in();//输入
(a*b).out();//输出
return 0;
}
03:字符环
-
描述
-
有两个由字符构成的环。请写一个程序,计算这两个字符环上最长连续公共字符串的长度。例如,字符串“ABCEFAGADEGKABUVKLM”的首尾连在一起,构成一个环;字符串“MADJKLUVKL”的首尾连在一起,构成一个另一个环;“UVKLMA”是这两个环的一个连续公共字符串。
输入
- 一行,包含两个字符串,分别对应一个字符环。这两个字符串之间用单个空格分开。字符串长度不超过255,且不包含空格等空白符。 输出
- 输出一个整数,表示这两个字符环上最长公共字符串的长度。 样例输入
-
ABCEFAGADEGKABUVKLM MADJKLUVKL
样例输出
-
6
用DP方法求两个字符串的最长连续公共字符串的长度的方法描述如下:定义f[i][j]表示以字符串1的第i位和字符串2的第j位为结尾的最长连续公共字符串的长度,可以得出状态转移方程为:f[i][j]=(s1[i]==s2[j]?f[i-1][j-1]+1:0)
求环上的最长连续公共字符串,使用倍增的思想,把两个字符串翻倍,例如AB翻倍为ABA,ABBCCCD翻倍为ABBCCCDABBCCC,然后再求最长连续公共字符串的长度。
注意:现在得出的答案还不是正确的答案,因为这样的做法可能会把一个元素使用两次。可以证明,如果存在着一个长度为n+1的最长连续公共字符串,那么一定存在一个长度为n的最长连续公共字符串,所以最后的答案就要输出min(ans,min(l1,l2))
复杂度分析:时间复杂度O(NM),空间复杂度O(NM),通过滚动数组法可以优化到O(min(N,M))(N,M是两个字符串的长度)
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=610;
char s1[maxn],s2[maxn];
int l1,l2,L1,L2,f[maxn][maxn],ans=0;
int main()
{
memset(f,0,sizeof f);
scanf("%s%s",s1,s2);
l1=strlen(s1);l2=strlen(s2);
for(int i=0;i<l1-1;i++)s1[i+l1]=s1[i];
for(int i=0;i<l2-1;i++)s2[i+l2]=s2[i];
L1=l1*2-1;L2=l2*2-1;
for(int i=0;i<L1;i++)for(int j=0;j<L2;j++)
if(s1[i]==s2[j])f[i+1][j+1]=f[i][j]+1,ans=max(ans,f[i+1][j+1]);
printf("%d\n",min(ans,min(l1,l2)));
return 0;
}