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
****************************************************************/

 

 

 

 

posted @ 2013-05-09 13:21  yefeng1627  阅读(394)  评论(0编辑  收藏  举报

Launch CodeCogs Equation Editor