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;    

}

 

你可能感兴趣的:(OJ)