• 7.31 基本算法1.1


    一。递归与递推

    方法:  思维模式,找本题所用的思想,找到目标组数,创建数组按顺序依次选择被选择的数---问题边界-----记录该数已选---求解子问题---回溯到上一问题,还原现场

                 常与枚举使用

     

    例题:ch201 费解的开关(递归实现枚举,状态压缩)

     

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 int pic[6][6];//存储输入
     6 int tmppic[6][6];//临时复制数组
     7 int di[]={0,0,0,1,-1};
     8 int dj[]={0,1,-1,0,0};
     9 
    10 void turn(int i,int j){//反转
    11     for(int k=0;k<5;k++){
    12         int tmpi=i+di[k],tmpj=j+dj[k];
    13         if(tmpi>=1 && tmpi<=5 && tmpj>=1 && tmpj<=5)
    14         {
    15             if(tmppic[tmpi][tmpj]==1) tmppic[tmpi][tmpj]=0;
    16             else tmppic[tmpi][tmpj]=1;
    17         }
    18     }
    19 }
    20 
    21 bool test(int i){//检测答案
    22     for(int j=1;j<=5;j++){
    23         if(tmppic[i][j]!=1) return false;
    24     }
    25     return true;
    26 }
    27 
    28 int solve(){
    29     int minans=25;
    30     for(int i=0;i<(1<<5);i++){
    31         memcpy(tmppic,pic,sizeof(pic));
    32         int ans=0;
    33         for(int j=0;j<5;j++){
    34             if((i>>j)&1) {turn(1,j+1);ans++;}
    35         }
    36         for(int j=2;j<=5;j++){
    37             for(int k=1;k<=5;k++){
    38                 if(tmppic[j-1][k]==0){
    39                     turn(j,k);
    40                     ans++;
    41                 }
    42             }
    43         }
    44         if(test(5)) minans=min(minans,ans);
    45     }
    46     return minans;
    47 }
    48 
    49 int main(){
    50     int t;
    51     scanf("%d",&t);
    52     while(t--){
    53         char tmp;
    54         for(int i=1;i<=5;i++){
    55              for(int j=1;j<=5;j++){
    56                  tmp=getchar();
    57                  while(tmp!='0'&&tmp!='1') tmp=getchar();
    58                  pic[i][j]=tmp-'0';
    59              }
    60          }
    61         int ans=solve();
    62         printf("%d
    ",ans>6?-1:ans);
    63     }
    64     return 0;
    65 }
    View Code

    方法:先枚举第一行的开关情况,再每个情况往下一行推看最后一行是否满足要求,则方案数+1

    核心:

      for(int j = 0; now; j++, now >>= 1) {

              if(now & 1)    press(0,j);

           }

     

    思考:看到这类题先想用递归枚举法是否比dfs要更简便,因为本题只要枚举第一行的情况之后每个情况的答案都只有一种,所以用递归枚举法更方便。先找思想,思维模式考虑是否其实情况答案唯一可以用递归枚举进行状态压缩,若每个情况都会分成更细的子问题则用dfs等搜索更优,不适合再用递归枚举(只适合结果单一不复杂)。

     

     

              poj1845(递归分治)/(数论 逆元+快速幂)

    要求的是A^B的所有因子的和之后再mod 9901的值。

    因为一个数A能够表示成多个素数的幂相乘的形式。即A=(a1^n1)*(a2^n2)*(a3^n3)...(am^nm)。所以这个题就是要求

    (1+a1+a1^2+...a1^n1)*(1+a2+a2^2+...a2^n2)*(1+a3+a3^2+...a3^n2)*...(1+am+am^2+...am^nm) mod 9901。

    对于每一个(1+a1+a1^2+...a1^n1) mod 9901

    等于 (a1^(n1+1)-1)/(a1-1) mod 9901,这里用到逆元的知识:a/b mod c = (a mod (b*c))/ b

    所以就等于(a1^(n1+1)-1)mod (9901*(a1-1)) / (a1-1)。

    至于前面的a1^(n1+1),快速幂。‘

     

      1 #include <iostream>
      2 #include <algorithm>
      3 #include <cmath>
      4 #include <vector>
      5 #include <string>
      6 #include <cstring>
      7 #pragma warning(disable:4996)
      8 using namespace std;
      9 #define M 9901
     10  
     11 long long p[50005];
     12 int prime[50005];
     13  
     14 void isprime()
     15 {
     16     int cnt = 0, i, j;
     17     memset(prime, 0, sizeof(prime));
     18     
     19     for (i = 2; i < 50005; i++)
     20     {
     21         if (prime[i] == 0)
     22         {
     23             p[++cnt] = i;
     24             for (j = 2 * i; j < 50005;j=j+i)
     25             {
     26                 prime[j] = 1;
     27             }
     28         }
     29     }
     30 }
     31  
     32 long long multi(long long A,long long n,long long k)
     33 {
     34     long long b=0;
     35     while(n>0)
     36     {
     37         if(n&1)
     38         {
     39             b=(b+A)%k;
     40         }
     41         n=n>>1;
     42         A=(A+A)%k;
     43     }
     44     return b;
     45 }
     46  
     47 long long getresult(long long A,long long n,long long k)
     48 {
     49     long long b = 1;
     50     while (n > 0)
     51     {
     52         if (n & 1)
     53         {
     54             b=multi(b,A,k);
     55         }
     56         n = n >> 1;
     57         A=multi(A,A,k);
     58     }
     59     return b;
     60 }
     61  
     62 void solve(long long A, long long B)
     63 {
     64     int i;
     65     long long ans = 1;
     66     for (i = 1; p[i] * p[i] <= A; i++)
     67     {
     68         if (A%p[i] == 0)
     69         {
     70             int num = 0;
     71             while (A%p[i] == 0)
     72             {
     73                 num++;
     74                 A = A / p[i];
     75             }
     76             long long m = (p[i] - 1) * 9901;
     77             ans *= (getresult(p[i], num*B + 1, m) + m - 1) / (p[i] - 1);
     78             ans %= 9901;
     79         }
     80     }
     81     if (A > 1)
     82     {
     83         long long m = 9901 * (A - 1);
     84         ans *= (getresult(A, B + 1, m) + m - 1) / (A - 1);
     85         ans %= 9901;
     86     }
     87     cout << ans << endl;
     88 }
     89  
     90 int main()
     91 {
     92     //freopen("i.txt","r",stdin);
     93     //freopen("o.txt","w",stdout);
     94     
     95     long long A, B;
     96     
     97     isprime();
     98     
     99     while (cin>>A>>B)
    100     {
    101           solve(A, B);
    102     }
    103     return 0;
    104 }
    View Code

     

    #include <cstdio>
    #include <cmath>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    const int mod=9901;
    int pow_mod(int a,int b)
    {
        a=a%mod;
        int s=1;
        while(b)
        {
            if(b&1)
                s=(s*a)%mod;
            a=(a*a)%mod;
            b=b>>1;
        }
        return s;
    }
    int sum(int a,int b)//求1+a+a^2+...+a^b
    {
        if(b==1)return 1;
        if(b&1)return (sum(a,b/2)*(1+pow_mod(a,b/2+1))+pow_mod(a,b/2))%mod;
        else return sum(a,b/2)*(1+pow_mod(a,b/2))%mod;
    }
    int main()
    {
        int a,b;
        while(cin>>a>>b)
        {
             if(a<=1||b==0){cout<<1<<endl;continue;}
            int ans=1,i,j,k,t,n,m;
            n=(int)sqrt(a+0.5);
            for(i=2;i<=n;i++)
            {
                if(a%i==0)
                {
                    t=0;
                    while(a%i==0){
                        a=a/i;
                        t++;
                    }
                    ans=ans*sum(i,t*b+1)%mod;
                }
            }
            if(a>1)
                ans=ans*sum(a,b+1)%mod;
            cout<<(ans+mod)%mod<<endl;    
        }
        return 0;
    }
    View Code

    思考:看到这类偏数学的题立马想思维,想数学公式与逆元,快速幂等数学方法,手写推导,此题需要考虑次方的奇偶性

              poj3889(分形)(坐标变换)

    参考:https://blog.csdn.net/ben_xsy/article/details/79288058

             

     

  • 相关阅读:
    父容器的flowover:hidden 必须配合父容器的宽高height width才能生效
    css使 同一行内的 文字和图片 垂直居中对齐?
    vim查找替换
    要让div中的float不会自动显示到下一行来?
    如何理解clear的css属性?
    div+css使多行文字垂直居中?
    VMnet1和V8
    unslider的用法详解
    json的中括号和大括号的使用?
    如何合理定价,定价定天下,必须要学会这个哦!
  • 原文地址:https://www.cnblogs.com/zyddd915/p/11280934.html
Copyright © 2020-2023  润新知