2013-5-6 训练赛总结

训练赛链接: http://www.acmore.net/contest.php?cid=1013

 

Problem A: Yard

题意:  n*m的格子,有树与空地,要求每个位置上下左右树的数量为偶数.求拔除与种植最小花费.

解法: 状态压缩, 第一行状态确定后,则所有行都确定. 然后枚举第一行状态,取个最小值即可.

View Code
#include<cstdio>

#include<cstring>

#include<cstdlib>

#include<algorithm>

using namespace std;

 

 

const int inf = 0x3f3f3f3f;

 

char A[110][110];

int B[110][110];

int a[110][110];

 

int n, m, res;

 

void gao(int &cnt){

    int mark = 0;       

    for(int i = 0; i < m; i++ ){

        if( i == 0 ){

            if( a[0][i+1] ) mark |= (1<<i);   

        }

        else if( i == m-1 ){

            if( a[0][i-1] ) mark |= (1<<i);   

        }

        else{

            mark |= ((a[0][i-1]+a[0][i+1])&1)<<i;

        }   

    }

     

    for(int i = 1; i < n; i++ ){

        // a[][]    

        for(int j = 0; j < m; j++){

            a[i][j] = mark&(1<<j) ? 1 : 0;

            if( a[i][j] != B[i][j] ){

                if(++cnt > res) return;

            }   

        }   

        // status           

        mark = 0;   

        for(int j = 0; j < m; j++){

            if( j == 0 ) mark |= ((a[i-1][j]+a[i][j+1])&1); 

            else if(j == m-1) mark |= ((a[i][j-1]+a[i-1][j])&1)<<j;

            else mark |= ((a[i][j-1]+a[i-1][j]+a[i][j+1])&1)<<j;

        }   

    }

    if( mark == 0 ) res = min( res, cnt );

}

int solve(){

    int Mark = (1<<m)-1 ;

    res = inf;

    for(int mark = 0; mark <= Mark; mark++){

        int cnt = 0;    

        for(int i = 0; i < m; i++){

            a[0][i] = (mark&(1<<i))?1:0;

            cnt += (a[0][i]!=B[0][i]);  

        }   

        gao( cnt );

    }   

    printf("%d\n", res);

}

int main(){

    while( scanf("%d%d",&m,&n) != EOF){

        for(int i = 0; i < m; i++)

            scanf("%s", A[i] );

        for(int i = 0; i < n; i++){ // col

            for(int j = 0; j < m; j++){ //  row

                if( A[j][i] == '#' ) B[i][j] = 1;

                else    B[i][j] = 0;

            }   

        }   

        solve();    

    }       

    return 0;

}

Problem B: ZZB的数学作业

题意: “把一个正整数M分成P个不超过K的正整数的和,满足分成的数不是N的倍数,并且P也不是N的倍数,求这样的P最小是多少?”

解法: 判定.  看了AC代码觉得好神奇. 有些地方不太明白为什么可以这样判定,感脚不严谨.,,,先贴份AC代码吧.

View Code
#include<cstdio>



typedef long long LL;



LL n, m, k;

int main(){

    while( scanf("%lld%lld%lld", &n,&m,&k) != EOF){

        if(n == 1){ printf("-1\n"); continue; }        

        if((n==2) && (m%2==0) ){ printf("-1\n"); continue; }

        if((m%n==0) && (k==1) ){ printf("-1\n"); continue; }    

        k = k>m?m:k;    

        while( k%n == 0 ) k--;

        LL cnt = m/k;

        LL left = m%k;

        if( left == 0 ){

            if(cnt%n == 0) cnt++;

        }    

        else{

            cnt++;    

            if(left%n == 0){

                if( (k-1)%n == 0 ) cnt++;    

            }    

            if(cnt%n == 0) cnt++;

        }    

        printf("%lld\n", cnt);    

    }

    return 0;

}

 

Problem C: 爱情测试

题意: 给出前三项a1a2a3,以及要求的项的编号n,并且数列{an}只可能是等差数列或者是首项为1的等比数列,要求A输出第n项模100007后的值。

解法:  判定下,然后根据等差或等比计算即可.

View Code
#include <iostream>

#include <cmath>

#include <cstring>

#include <cstdio>

#include <string>

#include <stdlib.h>

#include <algorithm>

using namespace std;

typedef long long LL;

const LL Mod= 100007;

LL a, b, c, n, d, q, ans; 

LL M_M( LL a, LL b )

{

    LL res=0, t=a;

    while( b ){

        if( b&1 )res=(res+t)%Mod;

        t=(t+t)%Mod;

        b>>=1;

    }

    return res;

}

LL P_M( LL a, LL b )

{

    LL res=1, t=a;

    while( b ){

        if( b&1 )res*=t, res%=Mod;

        t*=t, t%=Mod;

        b>>=1;

    }

    return res;

}

int cc( int d, int n )

{

    return (a+M_M(d, n-1))%Mod; 

}

int bb( int q, int n )

{

    return (a*P_M( q, n-1 ))%Mod;

}

int main( )

{

    while( scanf("%lld%lld%lld%lld", &a, &b, &c, &n)==4 ){

        if( a-b==b-c ){

            d=b-a;

            ans=cc(d, n);

        }

        else{

            q=b/a;

             

            ans=bb( q, n );

        }

        printf("%lld\n", ans);

    }

    return 0;

}

 

/**************************************************************

    Problem: 1518

    User: yefeng1627

    Language: C++

    Result: Accepted

    Time:0 ms

    Memory:1432 kb

****************************************************************/

Problem D: 除草

题意:  很长...

解法: 不会. 

Problem E: 友谊圈(Easy)

题意:  求一个最长上升序列, 要求 ai -aj >= i-j . 

解法:  因为有相对位置的影响,  预处理可以将 ai - i, 这样就消除了相对位置影响,就可以直接做一个最长上升子序列,即可. 注意 ai > 0. 

因为这里 N = 1e5, 需要一个 O(NlogN)的算法,  通过保存当前长度最小, 然后二分查找即可,实现 NlogN.

有个地方需要注意的是, 因为我们令 ai-i,去掉了相对位置影响,则找LIS时,即可高度相同。所以 idx[m] <= x 。

View Code
#include<cstdio>

 

const int N = 200010, inf = 0x3f3f3f3f;

 

int n, ln, a[N], f[N] = {0,1};

 

int find(int x){

    int l = 0, r = ln, m, res;

    while( l <= r ){

        m = (l+r)>>1;

        //printf("l = %d, r = %d, m = %d\n", l, r, m ); 

        if( f[m] <= x ) (res=m),(l=m+1);

        else    r = m-1;

        //printf("l = %d, r = %d\n", l, r );    

    }

    return res;

}

int main(){

    scanf("%d", &n);

    for(int i = 1; i <= n; i++){

        scanf("%d", &a[i]);

        a[i] -= i;

    }

    f[0] = -inf; ln = 0;

    for(int i = 1; i <= n; i++)

        if( a[i] >= 0 ){

            int t = find(a[i])+1;

            f[t] = a[i];

            if(t > ln) ln = t;

        }

    printf("%d\n", ln );

    return 0;

}

/**************************************************************

    Problem: 1523

    User: yefeng1627

    Language: C++

    Result: Accepted

    Time:7 ms

    Memory:2476 kb

****************************************************************/

Problem F: [USACO 1.5.3]特殊的质数肋骨

题意:  找出长度为 N ,其前缀都为素数的所有数.

解法: 搜索, 过程中判定, 判定用开根号的方式.即可

View Code
#include<cstdio>

#include<cstdlib>

#include<cstring>

#include<algorithm>

#include<cmath>

using namespace std;

 

 

int n;

 

bool legal(int x){

    if( x == 1 ) return false;  

    for(int i = 2; i*i <= x; i++)

        if( x%i == 0 ) return false;

    return true;

}

 

void dfs(int t, int x){

    if( t == n ){

        printf("%d\n",x);   

        return; 

    }

    for(int i = 0; i <= 9; i++){

        int tmp = x*10+i;

        if( legal(tmp) )

            dfs( t+1, tmp );    

    }

} 

int main(){

    while( scanf("%d",&n) != EOF){

        for(int i = 1; i <= 9; i++){

            if( legal(i) ){

                dfs( 1, i );    

            }   

        }           

    }   

    return 0;

}

/**************************************************************

    Problem: 1075

    User: yefeng1627

    Language: C++

    Result: Accepted

    Time:0 ms

    Memory:916 kb

****************************************************************/

Problem G: [USACO 1.4.4]母亲的牛奶

题意: 农民约翰有三个容量分别是A,B,C升的桶,A,B,C分别是三个从1到20的整数,最初,A和B桶都是空的,而C桶是装满牛奶的。有时,约翰把牛奶从一个桶倒到另一个桶中,直到被灌桶装满或原桶空了。当然每一次灌注都是完全的。由于节约,牛奶不会有丢失。写一个程序去帮助约翰找出当A桶是空的时候,C桶中牛奶所剩量的所有可能性。

解法: BFS搜索, 模型转换, {a,b,c},然后模拟转换过程,标记. 

View Code
#include<cstdio>

#include<cstring>

#include<cstdlib>

#include<queue>

#include<algorithm>

 

using namespace std;

 

int A, B, C;

bool vis[25][25][25];

 

struct node{

    int a,b,c;

}pre,nxt;

 

queue<node>Q;

 

void solve(){

 

    pre.a = 0, pre.b = 0, pre.c = C;

    while( !Q.empty() ) Q.pop();

    Q.push( pre );

    vis[0][0][C] = true;

    while( !Q.empty() ){

        pre = Q.front(); Q.pop();

         

        int a = pre.a, b = pre.b, c = pre.c;

        if( a > 0 ){

            if( b < B ){

                nxt.a = a-min(a,(B-b)); 

                nxt.b = b+min(a,(B-b)); 

                nxt.c = c;  

                if( !vis[nxt.a][nxt.b][nxt.c] )

                    Q.push( nxt ), vis[nxt.a][nxt.b][nxt.c] = true;

            }   

            if( c < C ){

                nxt.a = a-min(a,(C-c));

                nxt.b = b;

                nxt.c = c+min(a,(C-c));

                if( !vis[nxt.a][nxt.b][nxt.c] )

                    Q.push( nxt ), vis[nxt.a][nxt.b][nxt.c] = true;

            }   

        }

        if( b > 0 ){

            if( a < A ){

                nxt.a = a+min(b,(A-a));

                nxt.b = b-min(b,(A-a));

                nxt.c = c;

                if( !vis[nxt.a][nxt.b][nxt.c] )

                    Q.push( nxt ), vis[nxt.a][nxt.b][nxt.c] = true;

            }

            if( c < C ){

                nxt.a = a;

                nxt.b = b-min(b,(C-c));

                nxt.c = c+min(b,(C-c));

                if( !vis[nxt.a][nxt.b][nxt.c] )

                    Q.push( nxt ), vis[nxt.a][nxt.b][nxt.c] = true;

            }

        }   

        if( c > 0 ){

            if( a < A ){

                nxt.a = a+min(c,(A-a)); 

                nxt.b = b;

                nxt.c = c-min(c,(A-a));

                if( !vis[nxt.a][nxt.b][nxt.c] )

                    Q.push( nxt ), vis[nxt.a][nxt.b][nxt.c] = true;

            }

            if( b < B ){

                nxt.a = a;

                nxt.b = b+min(c,(B-b));

                nxt.c = c-min(c,(B-b));

                if( !vis[nxt.a][nxt.b][nxt.c] )

                    Q.push( nxt ), vis[nxt.a][nxt.b][nxt.c] = true;

            }

        }   

    }

}

int main(){

    while( scanf("%d%d%d",&A,&B,&C) != EOF){

        memset( vis, 0, sizeof(vis) );

        solve();

        bool tmp[25];

        memset(tmp,0,sizeof(tmp));

        for(int b = 0; b <= B; b++)

            for(int c = 0; c <= C; c++)

                tmp[c] |= vis[0][b][c];

        bool flag = false;  

        for(int i = 0; i <= C; i++)

            if( tmp[i] ){

                if( !flag ) printf("%d",i), flag =true;     

                else printf(" %d",i);

            }   

        puts("");

    }

    return 0;

}

/**************************************************************

    Problem: 1074

    User: yefeng1627

    Language: C++

    Result: Accepted

    Time:0 ms

    Memory:1032 kb

****************************************************************/

Problem H: [USACO 1.4.2]时钟

题意: 3*3的矩阵, 有10条规则,转换, 问最短的路径转换到要求状态.

解法: 还是一样BFS搜索, 使用标记. 处理有点麻烦. 

View Code
#include<cstdio>

#include<cstdlib>

#include<cstring>

#include<algorithm>

#include<queue>

using namespace std;

 

const int N = (int)5e5+10;

 

bool vis[4][4][4][4][4][4][4][4][4];

char mp[10];

bool flag;

char b[9][9];

 

struct Node{

    char p[10], kind;

    int f;

}Q[N], cur;

 

void init(){

    memset(b,0,sizeof(b));

    b[0][0]=b[0][1]=b[0][3]=b[0][4]=1;

    b[1][0]=b[1][1]=b[1][2]=1;

    b[2][1]=b[2][2]=b[2][4]=b[2][5]=1;

    b[3][0]=b[3][3]=b[3][6]=1;

    b[4][1]=b[4][3]=b[4][4]=b[4][5]=b[4][7]=1;

    b[5][2]=b[5][5]=b[5][8]=1;

    b[6][3]=b[6][4]=b[6][6]=b[6][7]=1;

    b[7][6]=b[7][7]=b[7][8]=1;

    b[8][4]=b[8][5]=b[8][7]=b[8][8]=1;

}

void gao(char *c ){

    vis[c[0]][c[1]][c[2]][c[3]][c[4]][c[5]][c[6]][c[7]][c[8]] = true;

}

bool legal(char *c){

    if(vis[c[0]][c[1]][c[2]][c[3]][c[4]][c[5]][c[6]][c[7]][c[8]]) 

        return false;

    return true;

}

bool over(char *c){

    if( vis[3][3][3][3][3][3][3][3][3] ) return true;

    return false;

}

int solve(){    

    memset( vis, 0, sizeof(vis));

    int l = 0, r = 0;   

    memcpy( Q[r].p, mp, 9*sizeof(char)); 

    Q[r].f = -1; Q[r++].kind = -1;

    gao( mp );  

    while( l < r ){

        cur = Q[l];

        if( over(cur.p) ) return l;     

         

        for(int i = 0; i < 9; i++){

            Node tmp = cur; 

            for(int j = 0; j < 9; j++){

                tmp.p[j] = (tmp.p[j]+b[i][j])%4;    

            }   

            if( legal(tmp.p) ){

                gao( tmp.p );

                tmp.f = l; tmp.kind = i+1;  

                Q[r++] = tmp;

                if( over(tmp.p) ) return r-1;   

            }   

        }

        l++;    

    }

}

void output(int d){

    if( Q[d].f == -1 ) return;

    output( Q[d].f );

    if( flag ) flag = false, printf("%d",Q[d].kind);

    else printf(" %d", Q[d].kind );

}

int main(){

    init(); 

    while( scanf("%d%d%d",&mp[0],&mp[1],&mp[2]) != EOF){

        scanf("%d%d%d",&mp[3],&mp[4],&mp[5]);

        scanf("%d%d%d",&mp[6],&mp[7],&mp[8]);

        for(int i = 0; i < 9; i++)

            mp[i] = mp[i]/3 - 1;

        int d = solve();

        flag = true;    

        output(d);

        puts("");   

    }   

    return 0;

}

/**************************************************************

    Problem: 1072

    User: yefeng1627

    Language: C++

    Result: Accepted

    Time:85 ms

    Memory:8984 kb

****************************************************************/

 

 

 

 

你可能感兴趣的:(总结)