被7整除

       时间限制:C/C++语言 2000MS;其它语言 4000MS
       内存限制:C/C++语言 65536KB;其它语言 589824KB
       题目描述:
       小萌非常喜欢能被7整除的数字,比如7,21,121996,等等。有一天她得到了n个 正整数,她想用这些数制造出更多的能够被7整除的数。于是她从这n个数中选出两个数,然后将一个数写在另一个数的前面,以此得到一个新的数。按这种方法她一共可以得到2X{n,2}个数,她想知道在这些数中,有多少个是能被7整除的。

输入

       第一行包含一个整数n。2≤n≤10的5次方
       第二行包含n个正整数ai。1 ≤ai≤10的9次方
输出 
       输出对应的答案。

样例输入
       3
       127 1996 12

样例输出
       4

Hint
       一共有4种组合方式,其中:把12写在1996前面得到121996;把127写在12前面得到12712;把1996写在12前面得到199612;把1996写在127前面得到1996127;都是可以被7整除的,其余的组合方式不能被7整除。
 
代码----------能处理10万条数据!
一.纯代码版
#include<iostream>
#include<fstream>
#include<ctime>
using namespace std;
int main()
{
    clock_t start = clock();
    int n,i,j,zc_num=0,cf_num=0;
    ifstream in("makebigdata.txt");
    //ifstream in("test2.txt");
    in>>n;
    int *ys=new int[n],*ws=new int[n],arr_same[100]={0};
    int arr_ys[10]={3,2,6,4,5,1,3,2,6,4};
    int arr_check[370]={0};
    for(i=0;i<370;i++)
        if(i%7==0)
            arr_check[i]=1;
    j=0;
    for(i=0;i<n;i++)
    {
        int ws_temp,ys_temp,temp;
        in>>temp;
        if(temp%7)
        {
            ys_temp=temp%7;
            ws_temp=-1;
            while(temp)
            {
                temp/=10;
                ws_temp++;
            }
            if(arr_same[ws_temp*10+ys_temp]>=1)
            {
                arr_same[ws_temp*10+ys_temp]++;
                cf_num++;
            }
            else
            {
                ys[j]=ys_temp;ws[j]=ws_temp;
                arr_same[ws_temp*10+ys_temp]=1;
                j++;
            }
        }
        else
            zc_num++;
    }
    int num=0;
    num=zc_num*(zc_num-1);
    for(i=0;i<n-zc_num-cf_num-1;i++)
        for(j=i+1;j<n-zc_num-cf_num;j++)
        {
            int num_temp=num+arr_check[arr_ys[ws[j]]*ys[i]+ys[j]];
            if(num_temp>num)
                num+=arr_same[ws[i]*10+ys[i]]*arr_same[ws[j]*10+ys[j]];
            num_temp=num+arr_check[arr_ys[ws[i]]*ys[j]+ys[i]];
            if(num_temp>num)
                num+=arr_same[ws[i]*10+ys[i]]*arr_same[ws[j]*10+ys[j]];
        }
    for(i=0;i<n-zc_num-cf_num;i++)
        if(arr_check[arr_ys[ws[i]]*ys[i]+ys[i]]==1)
            num+=arr_same[ws[i]*10+ys[i]]*(arr_same[ws[i]*10+ys[i]]-1);
    cout<<num<<endl;
    clock_t ends = clock();
    cout <<"Running Time : "<<(double)(ends - start)/ CLOCKS_PER_SEC << endl;
    return 0;
}
 运行效率刚刚滴!
二.注释版
 
#include<iostream>
#include<fstream>
#include<ctime>
using namespace std;
int main()
{
    clock_t start = clock();
    int n,i,j;
    ifstream in("makebigdata.txt");
    //ifstream in("test2.txt");
    in>>n;//读入整数个数n
    int *ys=new int[n]; //整数对7的余数
    int *ws=new int[n];//整数的位数
    /*
        比如:233456和788993 组成的数为:
              233456788993(数A1)=788993(数D)233456(数B)
                               =788993(数D)*1000000(数C)+233456(数B)
              233456788993(数A2)=233456(数B)788993(数D)
                               =233456(数B)*1000000(数C)+788993(数D)
              其中,数C比数D多一位,B和D对7整除分别有两种情况:
              [B1]:被7整除 [B2]:不能被7整除
              [D1]:被7整除 [D2]:不能被7整除
              以上面的数A2为例,四种组合:[B_Y],[C_Y],[D_Y]取值为[0,6],其中C_Y一定不为零,原因看下文,
              [B1][D1]
              [B_Y]*[C_Y]+[D_Y]=0*[C_Y]+0=0                 被7整除
              [B1][D2]
              [B_Y]*[C_Y]+[D_Y]=0*[C_Y]+[D_Y]=[D_Y]         不能被7整除
              [B2][D1]
              [B_Y]*[C_Y]+[D_Y]=[B_Y]*[C_Y]+0=[B_Y]*[C_Y]   由于7是质数,故[B_Y]*[C_Y]一定不是7的倍数
                                                            不能被7整除
              [B2][D2]=[B_Y]*[C_Y]+[D_Y]                    不确定能否被7整除
              因此本程序只需考虑第一种和第四种组合
 
        推理如下(以上面的数A2为例):
              (商)    (余数)
        [A]/7=[A_Z]...[A_Y] 
        [B]/7=[B_Z]...[B_Y]
        [C]/7=[C_Z]...[C_Y]
        [D]/7=[D_Z]...[D_Y]
        [A]%7=([B]*[C]+[D])%7
            =( (  ([B_Z]*7       +  [B_Y])* [C]         )%7 + [D]%7     )%7
            =( (  [B_Z]*7*[C]   +  [B_Y] * [C]         )%7 + [D_Y]      )%7
            =( (  0                  +  [B_Y] * [C] %7   )%7 + [D_Y]     )%7
            =(    [B_Y]*[C]                                    %7  +  [D_Y]     )%7
            =(    [B_Y]*([C_Z]*7+[C_Y])                %7  + [D_Y]%7  )%7
            =(   ([B_Y]*[C_Z]*7 +[B_Y]*[C_Y])      %7  + [D_Y]%7  )%7
            =(   (0                      +[B_Y]*[C_Y]%7)%7  + [D_Y]%7  )%7
            =(                                 [B_Y]*[C_Y]   %7  + [D_Y]%7  )%7
            =(    [B_Y]*[C_Y]                                        + [D_Y]    )%7 
        说明:arr_ys数组的下标表示整数的位数,为方便计算,比实际位数少取一位
              存储的内容为数[C]对7的余数[C_Y]
              下文中用法解释:arr_ys[ws[j]]*ys[i]+ys[j]
              ws[j]:整数的位数,为便于计算比实际位数少一位,如678位数为2位
              ws[j]=0,说明数D为1位数,数C=10
              ...
              ...
              ...
              ws[j]=9,说明数D为10位数,输C=10000000000
              arr_ys[ws[j]]=[C_Y]根据传入的整数位数构造余数
                arr_ys[ws[j]] *  ys[i] + ys[j]
              = [C_Y]         * [B_Y]] + [D_Y]
    */
    //构造C_Y集合
    int arr_ys[10]={
        10%7,
        100%7,
        1000%7,
        10000%7,
        100000%7,
        1000000%7,
        10000000%7,
        100000000%7,
        1000000000%7,
        1000000000%7*10%7
    };
    //静态化C_Y集合
    //int arr_ys[10]={3,2,6,4,5,1,3,2,6,4};
    //arr_check用来判断[C_Y]*[B_Y]]+[D_Y]能不能被7整除,初始化为0,表示不能被7整除
    //最大元素个数与被除数有关,本程序中7的最大余数为6,则arr_check数组的最大元素个数为6*6*6
    int arr_check[6*6+6+1]={0};
    for(i=0;i<6*6+6+1;i++)
        if(i%7==0)//能被7整除设置元素值为1
            arr_check[i]=1;
    /*
        统计相同特征数据的重复次数
        相同特征的说明,如果数[B]和数[D]具有相同的位数,且对7的余数也相同
        我们就认为这两数具有相同的特征,是重复数据
        从上文逻辑推理中,我们看到,数[A]对7的余数只与[B_Y],[C_Y]和[D_Y]有关
        下文中arr_same[ws_temp*10+ys_temp]的说明:
        ws_temp:当前读取数据的位数,比实际位数少1位,由于为int型数据,最大10位
                故ws_temp的取值范围为:0-9
        ys_temp:当前读取数据对7的余数,取值范围为:0-6
        arr_same[ws_temp*10+ys_temp]:具有相同位数和余数的数据出现的次数
    */
    int arr_same[100]={0};
    //记录能被7整除的数据的个数
    int zc_num=0;
    //记录不能被7整除具有相同特征的数据的重复次数
    int cf_num=0;
    j=0;
    //循环读取数据(遍历数据)
    for(i=0;i<n;i++)
    {
        int ws_temp,ys_temp;
        int temp;
        in>>temp;
        if(temp%7==0)//被7整除,计数
            zc_num++;
        else
        {
            ys_temp=temp%7;//被7除的余数
            ws_temp=-1;
            while(temp)//计算整数的位数,比实际位数少一位
            {
                temp/=10;
                ws_temp++;
            }
            //根据当前读取数据的位数和余数特征在arr_same中判断是否已经有该特诊的数据存在
            if(arr_same[ws_temp*10+ys_temp]>=1)//已存在,
            {
                arr_same[ws_temp*10+ys_temp]++;//更新该特诊的重复次数
                cf_num++;//更新总数据的重复次数
            }
            else//不存在,记录该数据的特征
            {
                ys[j]=ys_temp;//记录对7余数
                ws[j]=ws_temp;//记录位数
                j++;
                arr_same[ws_temp*10+ys_temp]=1;//设置该特诊的重复次数
            }
        }
    }
    //统计整个输入数据中两两组合能被7整除的组合个数
    int num=0;
    //能被整除的组合:[B1][D1]和[D1][B1]
    num=zc_num*(zc_num-1);
    //不确定的组合:[B2][D2]和[D2][B2]
    //能被7整除的数和arr_same[]数组中已具有相同特征的数不会再在ys[]和ws[]数组中记录它们的位数和对7余数
    //因此ys[]和ws[]数组中记录的都是彼此不具有相同特征的数据的位数和对7余数
    for(i=0;i<n-zc_num-cf_num-1;i++)
        for(j=i+1;j<n-zc_num-cf_num;j++)
        {
            //[B2][D2]组合
            int num_temp=num+arr_check[arr_ys[ws[j]]*ys[i]+ys[j]];
            //下述条件成立:
            //arr_check[arr_ys[ws[j]]*ys[i]+ys[j]]值为1,即[B2][D2]组合能被7整除
            //那么分别和B2,D2具有相同特征的两个数的组合也能被7整除
            //下文中arr_same[ws[i]*10+ys[i]]的值为和[B2]具有相同特征的数据的个数,包括[B2]
            //arr_same[ws[j]*10+ys[j]]的值为和[D2]具有相同特征的数据的个数,包括[D2]
            if(num_temp>num)
                num+=arr_same[ws[i]*10+ys[i]]*arr_same[ws[j]*10+ys[j]];
 
            //[D2][B2]组合
            num_temp=num+arr_check[arr_ys[ws[i]]*ys[j]+ys[i]];
            //解释参考[B2][D2]组合
            if(num_temp>num)
                num+=arr_same[ws[i]*10+ys[i]]*arr_same[ws[j]*10+ys[j]];
        }
    //[B2][B2]或者[D2][D2]组合,具有相同特征的数据内部自我两两组合
    //判断能不能被7整除
    for(i=0;i<n-zc_num-cf_num;i++)
        //[B2][B2]或者[D2][D2]组合能被7整除,类似于[B1][D1]和[D1][B1]计数
        if(arr_check[arr_ys[ws[i]]*ys[i]+ys[i]]==1)
            num+=arr_same[ws[i]*10+ys[i]]*(arr_same[ws[i]*10+ys[i]]-1);
    cout<<num<<endl;
    clock_t ends = clock();
    cout <<"Running Time : "<<(double)(ends - start)/ CLOCKS_PER_SEC << endl;
    return 0;
}

三.生成测试数据代码
 
#include<iostream>
#include<fstream>
#include<ctime>
using namespace std;
int main()
{
    int n=100000;
    ofstream out("makebigdata.txt");
    out<<n<<endl;
    srand((int)time(0));
    for(int i=1;i<=n;i++)
        out<<RAND_MAX*rand()+rand()<<" ";
    return 0;
}
原文地址:https://www.cnblogs.com/zhaopeng938/p/7532066.html