西山居初赛二 总结

hdu 4548 美素数

  用线性筛法筛选出10^6的素数,然后预处理统计下.. O(1)就能得到结果了.

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;

const int N = (int)1e6+10;

bool vis[N];
int p[N], sum[N];
void GetPrime(){
    memset(vis,0,sizeof(0));
    vis[1] = 1;
    int cnt = 0;
    for(int i = 2; i < N; i++){
        if( !vis[i] ) p[cnt++] = i;
        for(int j = 0; (j<cnt)&&(p[j]*i<N); j++){
            vis[ p[j]*i ] = 1;
            if( i%p[j] == 0 )break;
        }
    }
}
int Dight(int x){
    int s = 0;
    while(x) s+=x%10, x /= 10;
    return s;
}
void init(){
    GetPrime();
    sum[0] = sum[1] = 0;
    for(int i = 2; i < N; i++){
        sum[i] = sum[i-1];    
        if( !vis[i] && !vis[ Dight(i) ] ) sum[i]++; 
    }
}
int main(){
    init();
    int T;
    scanf("%d", &T);
    for(int Case = 1; Case <= T; Case++ ){
        int a, b;
        scanf("%d%d", &a,&b);
        printf("Case #%d: %d\n", Case, sum[b] - sum[a-1] );    
    }
    return 0;
}
View Code

hdu 4549 M斐波那契数列

  直接搞显然不行, 没有线性关系. 简单推导下有,  a, b, a^1*b^1, a^1*b^2 .... 可以知道a,b的幂满足Fib, 然后构造矩阵快速幂...就好了.还需要个性质: A^X = A^( X mod Eular(M) ) ( mod M ) .

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

typedef long long LL;
const int mod = (int)1e9+7;

struct Matrix{
    LL mat[2][2];
    void zero(){memset(mat,0,sizeof(mat)); }
    void unit(){zero();mat[0][0]=mat[1][1]=1;}    
}A, T;

void init_Matrix(){
    A.zero(); T.zero();
    A.mat[0][0]=A.mat[1][0]=1;
    T.mat[0][1]=T.mat[1][0]=T.mat[1][1]=1;
}
void print(Matrix a){
    printf("Matrix:\n");
    for(int i = 0; i < 2; i++){
        for(int j = 0; j < 2; j++)    
            printf("%d ", (int)a.mat[i][j]);
        puts("");
    }
}
Matrix mult(Matrix a, Matrix b){
    Matrix c; c.zero();
    for(int i = 0; i < 2; i++)
        for(int j = 0; j < 2; j++)
            for(int k = 0; k < 2; k++)
                c.mat[i][k]=(c.mat[i][k]+a.mat[i][j]*b.mat[j][k])%(mod-1);
    return c;
}
Matrix Pow(Matrix x,int n){
    Matrix c; c.unit();
    while( n ){
        if(n&1) c = mult(x,c);
        x = mult(x,x);
        n >>= 1;
    }
    return c;
}
LL Fib(int n){
    init_Matrix();
    A = mult( Pow(T,n-1), A );        
    return A.mat[0][0];
}
LL pow( LL x, int n ){
    LL c = 1;
    while(n){
        if(n&1) c = c*x%mod;
        x = x*x%mod;
        n >>= 1;
    }
    return c;
}
int main(){
    int a, b, n;    
    while( scanf("%d%d%d",&a,&b,&n) != EOF){
        if( n < 2 ){
            if( n == 0 ) printf("%d\n", a);
            else printf("%d\n", b);
        }                
        else{
            LL n1 = Fib( n-1 ), n2 = Fib( n );
    //        printf("n1 = %d, n2 = %d\n", (int)n1, (int)n2 );    
            LL ans = pow(a,n1)*pow(b,n2)%mod;    
            printf("%d\n", (int)ans );    
        }    
    }    
    return 0;
}
View Code

hdu 4550卡片游戏

  和波神讨论了好久...有0的情况好恶心. 最后邪恶的处理第一次出现0 的情况. 主要是出现了0, 则此时,在之后选定一个最小非0的数放在前面必定最优. 其他情况就是大的放后,小的放前面.....稀里哗啦写了好多..  A掉了后看到别人代码好短- - .....才发现好多地方做了无用工.......

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<string>
#include<algorithm>
using namespace std;

const int N = 110;

char s[N];
string t;
int len;
// S( i, len-1 )
void gao( int i ){
        char tm = '9'+10; 
        int pos = -1, cnt = 0;      
        for(int j = i; j < len; j++){    
            if( (s[j]!='0') && (tm>=s[j]) ) tm = s[j], pos = j;    
        }        
        if( (pos==-1) || ( (t[0]!='0')&&(s[pos]>t[0]))){
            for(int j = i; j < len; j++) t = t+s[j];    
        }
        else{
            for(int j = i; j < pos; j++){
                if( s[j] == '0' ) cnt++;    
                else t = t+s[j];    
            }    
            for(int j = 0; j < cnt; j++ ) t = '0' + t;    
            t = s[pos] + t;
            for(int j = pos+1; j < len; j++ ) 
                t = t + s[j];
        }    
        //printf("%s\n", t.c_str() );
}

int main(){
    int T;
    scanf("%d", &T);
    while( T-- ){
        scanf("%s", s);
        t.clear();
        len = strlen(s);
        int i = 1; t = s[0];
        if( s[0] == '0' ) gao(1);    
        else{
            while( (i<len) && (s[i]!='0') ){
                if( s[i] > t[0] ) t = t+s[i];
                else t = s[i] + t;
                i++;    
            }    
            if( i < len ) gao(i);    
        }
        printf("%s\n", t.c_str() );    
    }
    return 0;
}
View Code

  精简的代码思路:  就是找一个非0最小所在下标pos, 放在最前面. 其中 下标i < pos的, 用大在后,小在前.  然后i > pos的直接原样丢后面...不用考虑0的特殊情况....真心好..

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;

const int N = 110;

char s[N];

int main(){
    int _;
    scanf("%d", &_);
    while( _-- ){
        scanf("%s", s);
        string t;
        t += s[0];
        char ch = '9';
        int pos;
        for(int i = 0; s[i]; i++)
            if( (s[i]!='0') && (ch>=s[i]) ) ch = s[pos=i];
        for(int i = 1; s[i]; i++){
            if( i == pos ) t = s[i] + t;
            else if( i < pos ){
                if( s[i] <= t[0] ) t = s[i] + t;
                else t = t + s[i];
            }
            else t = t + s[i];    
        }
        printf("%s\n", t.c_str() );    
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/yefeng1627/p/3086931.html