zoukankan      html  css  js  c++  java
  • FOJ月赛2013年4月(校赛热身赛)

      A Jason的特殊爱好

        组合数学, 通过计算 [1,n]区间数量解决.

        假设n十进制表示位数为L,则通过统计长度为 L, L-1, ..., 1的数量来得出结果.    

        假设 n = a1,a2,a3,...,aL    // 十进制表示,其中a1为高位

        一.当长度小于L, 假设其为 len = 1,2,...,L-1

          则当前数 X = a1,a2,a3,...,a_len

          因为 Length(X) < Length(N), 所以任意的X都小于N,

          我们可以枚举 X中包含的1的个数,假设其为 K, 则 K = 0,1,2,...,len

          这里考虑, 因为高位不能为0,而其它位可以为 0.

          这里分两种情况:

            1. a_1 为1,  则 a_2,..,a_len ,中有 k-1位取1, 有 n-k位不取1,

    对于不取1的位置,其可以取(0,2,3,..,9) ,所以方案数为 C(n-1,k-1) * 9 ^ (n-k).

            1. a_1 不为1, 则 a_2,...,a_len,中有 k个为取1, 有n-k位不取1,

    对于不取1的位置, 若是a_1位置则只能取(2,3,..,9)共8种,而a_i ( i != 1 ) 则可以取( 0,2,..,9 )共9种,所以方案数位 8*9^(n-1-k)*C(n-1,k) 

          而 k 的取值范围为 (0,1,2,..,len ) 

          则总和为

                  注意 k = len 则要单独计算因为没有 a_1不为1的情况。

        二.当长度等于L

          若当前数 X = a1,a2,a3,...,a_L

          我们则一位一位处理, 当我们处理当 第i位, 则 (1,i-1)位 为1的数量为 cnt

          若 a_i < 0 , 则当前数 X 要小于 N, 则当前位只能取0. 

          若 a_i = 1 , 则当前数 X 要小于 N, 则当前位可以取0

              则 X' = a_1,a_2,...,a_i = 0, a_(i+1)..., a_L  

              此时, 对于 a_(i+1) ,..., a_L 位(共有L-i位)而言,取任意数都 会使 X' < N , 意味着都满足要求.

              则我们可以通过枚举 此区间1的个数, 假设其为 k = 0,1,2,.., L-i 

              则方案数为   (cnt+k)*C(L-i, k)*9^(L-i-k) 

          若 a_i > 1 , 则当前数 X 要小于 N, 则当前位可以取 ( 0,1,2, ..., (a_i-1) )

              这里其实和 a_i = 1 计算方式差不多, 只是要注意.

              若我们取 a_i = 1, 则 1的位数统计的时候就要多一个 即 cnt+1+k

              对于 a_i 不取 1, 则为  cnt+k ...

    View Code
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<map>
    #include<string>
    #include<cmath>
    using namespace std;
    
    typedef unsigned long long LL;
    
    LL C[20][20], fact[20];
    void init(){
        for(int i = 0; i <= 18; i++)
            C[i][0] = C[i][i] = 1;
        for(int i = 2; i <= 18; i++ ){
            for(int j = 1; j < i; j++)
                C[i][j] = C[i-1][j-1] + C[i-1][j];    
        }    
        fact[0] = 1;
        for(int i = 1; i <= 18; i++) fact[i] = fact[i-1]*9;
    }
    LL sum( LL x ){
        LL res = 0;
        if( x <= 0 ) return res; 
        int a[20], n = 0;
        LL t = x; while( t ){ t/=10; n++; }
        t = x;
        for(int i = n; i >= 1; i-- ){
            a[i] = t%10; t /= 10;
        }
    //    printf("n = %d\n", n );
    //    for(int i = 1; i <= n; i++){
    //        printf("%d ", a[i] );    
    //    }
    //    puts("");
        for(int L = 1; L <= n-1; L++ ){
            res += L;
            for(int k = 1; k < L; k++){
                res += 1LL*k*( fact[L-k]*C[L-1][k-1] + 8LL*fact[L-1-k]*C[L-1][k] );
            }
        }
    //    printf("res = %I64u\n", res ); //Accepted
        int c = 0;
        LL tmp = res;
        for(int i = 1; i <= n; i++){
            if( a[i] == 1 ){
                if( i > 1 ){
                    LL tmp = 0;
                    for(int j = 0; j <= n-i; j++){
                        tmp += (c+j)*( C[n-i][j]*fact[n-i-j] );     
                    }   
                    res += tmp;
                }
                c++;    
            }
            else if( a[i] > 1 ){
                LL tmp = 0;
                for(int j = 0; j <= n-i; j++){
                    tmp += (c+1+j)*( C[n-i][j]*fact[n-i-j] );    
                    if( i == 1 ) tmp += (a[i]-2)*(c+j)*( C[n-i][j]*fact[n-i-j] );
                    else tmp += (a[i]-1)*(c+j)*( C[n-i][j]*fact[n-i-j] );
                    
                }  
            //    printf("tmp = %I64u\n", tmp );
                res += tmp;
            }    
        } 
    //    printf("add = %I64u\n", res+c - tmp ); // Wrong Answer  1248
        return res + c;
    }
    int main(){
    //    freopen("test.out","w",stdout);
        init();
    //    printf("%I64u\n", sum( 1951 ) );
    //    for(LL b = 1; b <= 99999; b++ ){
        LL a , b;
        while( scanf("%I64u%I64u", &a,&b) != EOF ){  
            if( a > b ) swap( a, b );
            printf("%I64u\n", sum(b) - sum(a-1) );
    //        if( b == 1951)    printf("sum(1951)=%I64u\n", sum(1951) );
    //        if( sum(b) == 1416 ) printf("b = %I64u\n", b );
    //    }
        }
        return 0;    
    }

      C 模拟..

    View Code
    #include <iostream>
    #include <cmath>
    #include <cstring>
    #include <cstdio>
    #include <string>
    #include <stdlib.h>
    #include <algorithm>
    using namespace std;
    int T, N, x; 
    int gcd( int x, int y )
    {
        return y==0?x:gcd( y, x%y);
    }
    struct Node
    {
        int x, y, z;
        bool operator < ( const Node &a )const{
            return z>a.z;    
        }
    }ans[15]; 
    bool vis[15];
    
    int main( )
    { 
        scanf( "%d", &T);
        while( T -- ){
            scanf( "%d", &N );
            memset( vis, 0, sizeof(vis));
            int n = 0, idx = 0;
            for( int i=0; i<N; ++ i ){
                scanf("%d", &x );
                if( x != 0 ){
                    ans[n++].x=x;
                    vis[i] = 1;
                }
            }    
            for( int i=0; i<N; ++ i ){
                scanf( "%d", &x );
                if( vis[i] == 1 ){
                    ans[idx].y=x+1;
                    int t= gcd( abs(ans[idx].x), abs(ans[idx].y) );
                    ans[idx].x/= abs(t);
                    ans[idx].y/= abs(t); 
                //printf( "~~~~~~ %d %d\n", ans[i].x, ans[i].y ); 
                    ans[idx++].z=x+1;
                }
            }
            
            
            sort( ans, ans+n );
            if( abs(ans[0].y)>1 )
                printf( "%d%/%d", ans[0].x, ans[0].y );
            else if( abs(ans[0].x)>1 ) printf( "%d", ans[0].x );
            else if( abs(ans[0].x) == 1 && ans[0].x < 0 ) printf( "-" );
            if( ans[0].z>0 ){
                if( ans[0].z>1 ){
                    printf( "x^%d", ans[0].z );
                }
                else printf( "x" ); 
            }
            for( int i=1; i<n; ++ i ){
                if( abs(ans[i].y)>1 )    printf( "%+d%/%d", ans[i].x, ans[i].y );
                else if( abs(ans[i].x)>1 )printf( "%+d", ans[i].x );
                else if( abs(ans[i].x)==1 )printf( ans[i].x==1?"+":"-" ); 
                if( ans[i].z>0 ){
                    if( ans[i].z>1 )
                        printf( "x^%d", ans[i].z );
                    else printf( "x" ); 
                }
                    
            }
            puts( "" ); 
            
        }
        return 0;
    }

      H DFS减枝..

        因为 9! 等价 1e6 在算上比较, 1e7 算法还是能够跑的..处理上其实可以优化掉  10次左右的比较 

        时间复杂度就为 1e6左右了.

    View Code
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #define MIN(a,b) (a)<(b)?(a):(b)
    const int inf = 0x3fffffff;
     
    int g[15][15], a[15], n, len;
    int ans;
    int b[15];
    
    bool vis[10];
    
    void dfs( int num, int sum ){
        if( sum > ans ) return;
        if( num == len ){ 
            if( sum < ans ) ans = sum;
            return;
        }    
        for(int i = 0; i < len; i++){
            if( !vis[i]  ){ 
                if( num == 0 ){
                    if( a[i] == 0 ) continue;
                    vis[i] = 1;
                    b[num] = a[i];
                    dfs( num+1, 0 );
                    vis[i] = 0;
                }
                else{ // num > 0 
                    if( sum + g[a[i]][b[num-1]] < ans ){
                        vis[i] = 1;
                        b[num] = a[i];
                        dfs( num+1, sum+g[a[i]][b[num-1]] );
                        vis[i] = 0;    
                    }
                }
            }    
        }
    } 
    int main(){
        int T, X;
        scanf("%d", &T);
        while( T-- ){
            scanf("%d", &X );
            for(int i = 0; i < 10; i++)
                for(int j = 0; j < 10; j++ )
                    scanf("%d", &g[i][j] );
            ans = inf;len = 0;
            int t = X;
            
            while( t ){
                a[len++] = t%10;
                t /= 10;    
            }
            memset( vis, 0, sizeof(vis) );
            dfs( 0, 0 );
            printf("%d\n", ans );
        }    
        return 0;    
    }
  • 相关阅读:
    高阶函数 练习
    斐波那契数列(Fibonacci sequence)递归函数
    顺序循环队列的基本操作(二)
    顺序循环队列基本操作(一)
    顺序栈的基本操作
    双链表的插入删除
    头插法实现链表逆置
    带头结点单链表的基本操作
    顺序表基本操作
    实现原数组列变成行,再将每一行首尾倒置
  • 原文地址:https://www.cnblogs.com/yefeng1627/p/3002797.html
Copyright © 2011-2022 走看看