2017.11.6——2017.11.12
周一做的总结,都忘了上一周经历了什么,大概就是双十一吧= =;
本周在51nod上做了很多题。
先来
1.N的阶乘
这是一个大数的阶乘,很有意思。
其实思路很简单,就是将最后的结果分段保存,然后输出。
#include <stdio.h>
#define _MAX 100000000
int main()
{
int n, i, j, m;
long long a[10000], c;
scanf("%d",&n);
m = 0;
a[0] = 1;
for(i = 1; i <= n; i++)
{
c = 0;
for(j = 0; j <= m; j++) //每一个结果片段都要相乘
{
a[j] = a[j] * i + c;
c = a[j] / _MAX;
a[j] %= _MAX;
}
if(c > 0)
{
m++;
a[m] = c;
}
}
printf("%lld", a[m]);
for(i = m - 1; i >= 0; i--)
printf("%0.8lld", a[i]);
printf("\n");
return 0;
}
2.N阶乘的长度
这道题就是数学,贴一个公式出来(Stirling公式)。
#include <cstdio>
#include <math.h>
#define pi 3.1415926
#define e 2.71828182845
int main()
{
long long n,res;
scanf("%lld",&n);
res=(log10(2*pi*n)*0.5+n*log10(n/e))+1; //注意向下取整后加1
printf("%lld",res);
}
3.逆序数
这个题用了分治的思想,虽然我还不太会。
本题用的是收录的比较好的方法。(有一种方法是在MSort里面不停开数组进行存储排好序的数字,这样递归次数太多容易爆点)开a,b两个数组,注意因为开了两个一模一样的数组,在分割的时候是来回反着调用(即注意a、b数组的调用)。
#include <stdio.h>
#define maxn 50010
long ans=0;
void Merge(long *a,long *b,int first,int mid,int last)
{
int i=first,j=mid+1;
int cur=first;
while(i<=mid && j<=last)
{
printf(""); //之前不要这个就会RE 不知道为什么
if(a[i]<=a[j])
{
b[cur++]=a[i++];
}
else
{
b[cur++]=a[j++];
ans+=mid-i+1;
}
}
while(i<=mid)
{
b[cur++]=a[i++];
}
while(j<=last)
{
b[cur++]=a[j++];
}
}
void MSort(long *a,long *b,int first,int last)
{
int mid;
if(first<last)
{
mid=(first+last)/2;
MSort(b,a,first,mid);
MSort(b,a,mid+1,last);
Merge(a,b,first,mid,last);
}
}
int main()
{
int N,i=1;
long a[maxn];
long b[maxn];
scanf("%d",&N);
for(;i<=N;i++)
{
scanf("%ld",&a[i]);
b[i]=a[i];
}
MSort(a,b,1,N);
printf("%ld\n",ans);
return 0;
}
4.gcd和lcm
gcd
#include<cstdio>
long long gcd(long long a,long long b)
{
if(a==b || b==0)
{
return a;
}
else return gcd(b,a%b);
}
int main()
{
long long a,b;
scanf("%lld %lld",&a,&b);
printf("%lld",gcd(a,b));
}
lcm
#include <cstdio>
long long gcd(long long a,long long b)
{
long long temp=a<b?a:b; //注意
while(a%b!=0)
{
temp=a%b;
a=b;
b=temp;
}
return temp;
}
int main()
{
long long a,b;
scanf("%lld %lld",&a,&b);
printf("%lld",a*b/gcd(a,b));
return 0;
}
虽然我写的不是很简单,但是毕竟很基本,可以看一看,还是有坑点的。
5.最长公共子序列
题目要求找到两个字符串的最长公共子序列(不要求子序列连续)
//这种题的思想一直不是很会(动态规划??)
#include <cstdio>
#include <cstring>
#include <algorithm>
int cata[1050][1050];
char a[1050],b[1050],str[1050];
int lena,lenb;
int maxn(int a,int b)
{
return a>b?a:b;
}
int main(void)
{
memset(cata,0,sizeof(a));
scanf("%s %s",a,b);
lena=strlen(a);
lenb=strlen(b);
for(int i=1;i<=lena;i++)
{
for(int j=1;j<=lenb;j++)
{
if(a[i-1]==b[j-1])
{
cata[i][j]=cata[i-1][j-1]+1;
}
else
{
cata[i][j]=maxn(cata[i-1][j],cata[i][j-1]);
}
}
}
int k=1050;
int i=lena,j=lenb;
while(i&&j)
{
if(a[i-1]==b[j-1])
{
str[k]=a[i-1];
i--;
j--;
k--;
}
else
{
if(cata[i-1][j]<=cata[i][j-1])
{
j--;
}
else
{
i--;
}
}
}
/*
for(int m=0;m<lena;m++)
{
for(int n=0;n<lenb;n++)
{
printf("%d ",cata[m][n]);
}
printf("\n");
}
*/
//str[k]='\0';
//strrev(str);
printf("%s",str+k+1);
}
6.大数的加减乘法
很有意思,看到了很多很强的方法,有时间另开一个随手。
!!
7.A^B Mod C
这道题最有意思的点就是用到了快速乘法(与矩阵的快速幂,斐波拉契用矩阵来求解一样有意思)
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
long long ans[10000];
long long length;
int findregu(long long a,long long b,long long c)
{
int t=1;
a=a%c;
while(b>0)
{
if(b%2==1) t=t*a%c;
a=a*a%c;
b=b/2;
}
return t;
}
int main()
{
long long a,b,c;
scanf("%lld %lld %lld",&a,&b,&c);
printf("%d",findregu(a,b,c));
}
//嗯 好像没用到
乘法快速幂的思想就是把指数化为二进制,二进制从小到大前推,同时a自乘得到temp,每遇到1就把temp与ans相乘存在ans,推完即结束。