打卡第二十三天(问题:扩展欧几里得算法+试探法,杨辉三角问题,KMP算法)

1.HDU1576 A/B【扩展欧几里得算法+试探法】

Problem Description
要求(A/B)%9973,但由于A很大,我们只给出n(n=A%9973)(我们给定的A必能被B整除,且gcd(B,9973) = 1)。
 

Input
数据的第一行是一个T,表示有T组数据。
每组数据有两个数n(0 <= n < 9973)和B(1 <= B <= 10^9)。
 

Output
对应每组数据输出(A/B)%9973。
 

Sample Input

2 1000 53 87 123456789
 

Sample Output

7922 6060
 

Author
xhd
 

Source
HDU 2007-1 Programming Contest


问题链接:HDU1576 A/B

问题分析:

这个问题有两种解法,一是用扩展欧几里得算法,二是用试探法。似乎后一种方法更快。


解法一:可以用解整数的不定方程来解决,即使用扩展欧几里德算法。

根据题意,输入的n=A%9973(没有输入A),A%B=0(A必能被B整除),B与9973互素(GCD(B,9973)=1)。

解题过程首先是建立方程,然后才能编写程序。

设x=(A/B)%9973(x是最终想计算的值),则9973k+x=A/B(k为整数),得A=9973Bk+xB。

因为n=A%9973与A=9973Bk+xB,所以xB%9973=n,得xB=n+9973y。

故:(x/n)B+(-y/n)9973=1=GCD(B,9973),该方程有解。

要求x和y,先求X=x/n和Y=-y/n,即先解方程BX+9973Y=1。

最后,x=X*n。

需要注意的是,求得的x有可能是负值,需要进行调整。

不过,这个计算方法好像比较花时间。


解法二:试探法

根据题意,输入的n=A%9973(没有输入A),A%B=0(A必能被B整除),B与9973互素(GCD(B,9973)=1)。

解题过程首先是建立方程,然后才能编写程序。

设x=(A/B)%9973(x是最终想计算的值,满足0<=x<=9972),则9973k+x=A/B(k为整数),得A=9973Bk+xB。

因为n=A%9973与A=9973Bk+xB,所以xB%9973=n,得xB=n+9973y,亦得xB-n=9973y。

故:(xB-n)%9973=0

对于上式,只需要用试探法就可以求得x。这样,程序运行速度相当快。

需要主意的是,变量类型为long时没有AC,改为long long就AC了,有点奇怪。也许评价系统所用编译版本的long类型不是64位的,才有这种情况。


扩展欧几里德算法解本问题的方法,时间上则比较慢。试探法有时也是高效率的。

AC的C语言程序如下(解法一):

#include<stdio.h>
long exgcd(long a,long b,long *x,long *y)
{
    long x0=1,y0=0,x1=0,y1=1;
    long r,q;
    *x=0;
    *y=1;
    r=a%b;
    q=(a-r)/b;
    while(r)
    {
        *x=x0-q*x1;
        *y=y0-q*y1;
        x0=x1;
        y0=y1;
        x1=*x;
        y1=*y;
        a=b;
        b=r;
        r=a%b;
        q=(a-r)/b;
    }
    return b;
 }
 int main(void)
 {
     int t,i;
     long n,b,a=9973,x,y;
     scanf("%d",&t);
     for(i-0;i<t;i++){
         scanf("%ld%ld",&n,&b);
         exgcd(b,a,&x,&y);
         x=(x+a)%a;
         printf("%ld\n",x*n%a);
     }
     return 0;
 }

AC的C语言程序如下(解法二):

#include<stdio.h>
int main(void)
{
    int i,t,j;
    long long n,b,a=9973;
    scanf("%d",&t);
    for(i=0;i<t;i++){
        scanf("%lld%lld",&n,&b);
        for(j=0;j<a;j++)
        if((j*b-n)%a==0){
            printf("%d\n",j);
            break;
        }
    }
    return 0;

}

2.I00001 杨辉三角

杨辉三角国际上称为Pascal三角形。

杨辉三角与菲波拉契数列也是有关系的,看以下的图就知道了。

这里给出来两种方法的实现,一是使用二维数组来存储杨辉三角,二是使用一维数组来存储杨辉三角并且一边计算一边输出结果。

使用一维数组作为存储,实现打印杨辉三角,需要的技巧更高一些。

#include<stdio.h>
//使用二维数组的杨辉三角
void pascal1()
{
    int n,i,j;
    scanf("%d",&n);
    int pascal[n][n];
    for(i=0;i<n;i++)
    for(j=0;j<=i;j++){
        if(j==0||j==i)
        pascal[i][j]=1;
        else
        pascal[i][j]=pascal[i-1][j]+pascal[i=1][j-1];
    }
    for(i=0;i<n;i++){
        for(j=0;j<=i;j++)
        printf("%d",pascal[i][j]);
        printf("\n");
    }
 }
 //使用一维数组的杨辉三角
 void pascal2()
 {
     int n,i,j;
     scanf("%d",&n);
     int pascal[n];
     for(i=0;i<n;i++){
         for(j=i;j>=0;j--){
             if(j==i||j==0)
             pascal[j]=1;
             else
             pascal[j]+=pascal[j-1];
             printf("%d",pascal[j]);
         }
         printf("\n");
     }
  }
  int main(void)
  {
      pascal1();
      pascal2();
      return 0;
  }

3.KMP算法(C语言版)

有关字符串匹配的最有效的算法。

其算法复杂度为两个字符串的长度之和(m+n)。

#include<stdio.h>
#include<string.h>
void setnext(char t[],int next[])
{
    next[0]=-1;
    int i;
    for(i=1;i<strlen(t);i++){
        int j=next[i-1];
        while(t[i]!=t[j+1]&&j>=0)
        j=next[j];
        if(t[i]==t[j+1])
        next[i]=j+1;
        else
        next[i]=0;
    }
}
int count_kmp(char s[],char t[],int next[])
{
    int t_size=strlen(t);
    setnext(t,next);
    int index,count=0;
    for(index=0;index<strlen(s);++index){
    int pos=0;
    int iter=index;
    while(pos<t_size&&iter<strlen(s)){
        if(s[iter]==t[pos]){
            ++iter;
            ++pos;
        }else{
            if(pos==0)
            ++iter;
            else
            pos=next[pos-1]+1;
        }
        if(pos==t_size&&(iter-index)==t_size)
        ++count;
        
    }
    return count;
}
int main(void)
{
    char s[]="abaabcacabaabcacabaabcacabaabcacabaabcac";
    char t[]="ab";
    int next[strlen(t)];
    int count=count_kmp(s,t,next);
    printf("count=%d\n",count);
    return 0;
}

4.KMP算法(C++版)

有关字符串匹配的最有效的算法。

其算法复杂度为两个字符串的长度之和(m+n)。

与C语言版本想比,这个版本只是使用C++语法,功能还是被封装在函数中。

#include<stdio.h>
#include<iostream>
#include<stdlib.h>
#include<vector>
using namespace std;
inline void NEXT(const string &T,vector<int> &next)
{
    next[0]=-1;
    for(int i=1;i<T.size();i++){
        int j=next[i-1];
        while(T[i]!=T[j+1]&&j>=0)
        j=next[j];
        if(T[i]==T[j+1])
        next[i]=j+1;
        else
        next[i]=0;
    }
}
inline string::size_type COUNT_KMP(const string &s,const string &T)
{
    vector<int> next(T.size());
    NEXT(T,next);
    string::size_type index,count=0;
    for(index=0;index<S.size();++index){
        int pos=0;
        string::size_type iter=index;
        while(S[iter]==T[pos]){
            ++iter;
            ++pos;
        }else{
            if(pos==0)
            ++iter;
            else
            pos=next[pos-1]+1;
        }
    }
    if(pos==T.size()&&(iter-index)==T.size())
    ++count;
}
return count;
}
int main(void)
{
    string S="abaabcacabaabcacabaabcacabaabcacabaabcac";
    string T="ab";
    string::size_type count=COUNT_KMP(S,T);
    cout<<count<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/huangluping12345/article/details/83095428
今日推荐