二月二十五日总结

2月25日训练赛

NOIP2008年复赛
一:
1. 笨小猴
(word.pas/c/cpp)
【问题描述】
笨小猴的词汇量很小,所以每次做英语选择题的时候都很头痛。但是他找到了一种方法,经试验证明,用这种方法去选择选项的时候选对的几率非常大!
这种方法的具体描述如下:假设maxn是单词中出现次数最多的字母的出现次数,minn是单词中出现次数最少的字母的出现次数,如果maxn-minn是一个质数,那么笨小猴就认为这是个Lucky Word,这样的单词很可能就是正确的答案。
【输入】
输入文件word.in只有一行,是一个单词,其中只可能出现小写字母,并且长度小于100。
【输出】
输出文件word.out共两行,第一行是一个字符串,假设输入的的单词是Lucky Word,那么输出“Lucky Word”,否则输出“No Answer”;
第二行是一个整数,如果输入单词是Lucky Word,输出maxn-minn的值,否则输出0。
【输入输出样例1】
word.in word.out
error Lucky Word
2
【输入输出样例1解释】
单词error中出现最多的字母r出现了3次,出现次数最少的字母出现了1次,3-1=2,2是质数。
【输入输出样例2】
word.in word.out
olympic No Answer
0
【输入输出样例2解释】
单词olympic中出现最多的字母i出现了2次,出现次数最少的字母出现了1次,2-1=1,1不是质数。

由于n<100所以直接用桶排,然后判断max-min是否为素数就可以了(可以只用根号n判断素数但数据太水随便了)

/********************
测试通过 Accepted

总耗时: 3 ms
0 / 0 数据通过测试.
运行结果
测试点#word1.in  结果:AC    内存使用量:  256kB     时间使用量:  0ms     
测试点#word10.in  结果:AC    内存使用量:  128kB     时间使用量:  1ms     
测试点#word2.in  结果:AC    内存使用量:  256kB     时间使用量:  0ms     
测试点#word3.in  结果:AC    内存使用量:  256kB     时间使用量:  0ms     
测试点#word4.in  结果:AC    内存使用量:  256kB     时间使用量:  0ms     
测试点#word5.in  结果:AC    内存使用量:  128kB     时间使用量:  1ms     
测试点#word6.in  结果:AC    内存使用量:  256kB     时间使用量:  0ms     
测试点#word7.in  结果:AC    内存使用量:  256kB     时间使用量:  0ms     
测试点#word8.in  结果:AC    内存使用量:  256kB     时间使用量:  0ms     
测试点#word9.in  结果:AC    内存使用量:  256kB     时间使用量:  1ms 
*********************/
#include 
#include 
#include 
#include 
using namespace std;

const int oo = 0x3f3f3f3f;

char s[105];
int a[30];

int main() {
    scanf( "%s", &s );
    int len = strlen (s);
    memset( a, 0, sizeof(a) );
    for ( int i = 0; i < len; i++ ) 
    a[s[i]-'a']++;
    int maxx = 0, minn = oo;
    for ( int i = 0; i < 26; i++ ) {
        if ( a[i] != 0 ) {
            if ( a[i] > maxx ) maxx = a[i];
            if ( a[i] < minn ) minn = a[i];
        }
    }
    int num = maxx - minn;
    int j;
    for ( j = 2; j <= num - 1; j++ )
    if ( num%j == 0 ) break;
    if ( j == num ) {
        printf("Lucky Word\n");
        printf("%d\n",num);
        return 0;
    }
    else {
        printf("No Answer\n");
        printf("0\n");
        return 0;
    }
}

二:
2. 火柴棒等式
(matches.pas/c/cpp)
【问题描述】
给你n根火柴棍,你可以拼出多少个形如“A+B=C”的等式?等式中的A、B、C是用火柴棍拼出的整数(若该数非零,则最高位不能是0)。用火柴棍拼数字0-9的拼法如图所示:

注意:
1. 加号与等号各自需要两根火柴棍
2. 如果A≠B,则A+B=C与B+A=C视为不同的等式(A、B、C>=0)
3. n根火柴棍必须全部用上

【输入】
输入文件matches.in共一行,又一个整数n(n<=24)。
【输出】
输出文件matches.out共一行,表示能拼成的不同等式的数目。

【输入输出样例1】
matches.in matches.out
14 2
【输入输出样例1解释】
2个等式为0+1=1和1+0=1。

【输入输出样例2】
matches.in matches.out
18 9
【输入输出样例2解释】
9个等式为:
0+4=4
0+11=11
1+10=11
2+2=4
2+7=9
4+0=4
7+2=9
10+1=11
11+0=11

暴力,这道题打表可以过,因为n<24 再减去四根火柴就最大20
那么20火柴组成的最大的数字为11111,那么直接把1—11111这些数字的火柴根数算出来就可以了在枚举两个加数判断

/********************
测试通过 Accepted

总耗时: 10 ms
0 / 0 数据通过测试.
运行结果
测试点#matches1.in  结果:AC    内存使用量:  364kB     时间使用量:  1ms     
测试点#matches10.in  结果:AC    内存使用量:  360kB     时间使用量:  1ms     
测试点#matches2.in  结果:AC    内存使用量:  364kB     时间使用量:  1ms     
测试点#matches3.in  结果:AC    内存使用量:  360kB     时间使用量:  1ms     
测试点#matches4.in  结果:AC    内存使用量:  360kB     时间使用量:  1ms     
测试点#matches5.in  结果:AC    内存使用量:  364kB     时间使用量:  1ms     
测试点#matches6.in  结果:AC    内存使用量:  364kB     时间使用量:  1ms     
测试点#matches7.in  结果:AC    内存使用量:  364kB     时间使用量:  1ms     
测试点#matches8.in  结果:AC    内存使用量:  360kB     时间使用量:  1ms     
测试点#matches9.in  结果:AC    内存使用量:  364kB     时间使用量:  1ms  
********************/
#include 
#include 
#include 
using namespace std;

struct date{
    int tot, num[12000];
    date() {
        tot = 0;
    }
};
date gun[30];
int a[11] = {6,2,5,5,4,5,6,3,7,6};
int n;
int main() {
    freopen("matches.in","r",stdin);
    freopen("matches.out","w",stdout);
    int res = 0;
    scanf( "%d", &n );
    n = n - 4;
    for ( int i = 0; i <= 12000; i++ ) {
        int k = i, sum = 0;
        do
        {
            sum += a[k%10];
            k /= 10;
        }while ( k!= 0 );
        if ( sum <= n )
        gun[sum].tot++;
        gun[sum].num[gun[sum].tot] = i;
    }
    for ( int i = 2; i <= n; i++ ) {
        for ( int j = 2; j <= n; j++ ) {
            int last = n - i - j;
            if ( last < 0 ) continue;
            for ( int a1 = 1; a1 <= gun[i].tot; a1++ )
                for ( int b1 = 1; b1 <= gun[j].tot; b1++ )
                    for ( int c1 = 1; c1 <= gun[last].tot; c1++ )
                    if ( (gun[i].num[a1] + gun[j].num[b1]) == gun[last].num[c1] ) {
                    //  printf("%d %d %d\n",gun[i].num[a1], gun[j].num[b1], gun[last].num[c1]);
                        res++;
                    } 
        }
    }
    printf( "%d\n", res );
    return 0;
}

三:
3. 传纸条
(message.pas/c/cpp)
【问题描述】
小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题。一次素质拓展活动中,班上同学安排做成一个m行 、n列的矩阵,而小渊和小轩被安排在矩阵对角线的两端,因此,他们就无法直接交谈了。幸运的是,他们可以通过传纸条来进行交流。纸条要经由许多同学传到对方手里,小渊坐在矩阵的左上角,坐标(1,1),小轩坐在矩阵的右下角,坐标(m,n)。从小渊传到小轩的纸条只可以向下或者向右传递,从小轩传给小渊的纸条只可以向上或者向左传递。
在活动进行中,小渊希望给小轩传递一张纸条,同时希望小轩给他回复。班里每个同学都可以帮他们传递,但只会帮他们一次,也就是说如果此人在小渊递给小轩纸条的时候帮忙,那么在小轩递给小渊的时候就不会再帮忙。反之亦然。
还有一件事情需要注意,全班每个同学愿意帮忙的好感度有高有低(注意:小渊和小轩的好心程度没有定义,输入时用0表示),可以用一个0-100的自然数来表示,数越大表示越好心。小渊和小轩希望尽可能找好心程度高的同学来帮忙传纸条,即找到来回两条传递路径,使得这两条路径上同学的好心程度只和最大。现在,请你帮助小渊和小轩找到这样的两条路径。

【输入】
输入文件message.in的第一行有2个用空格隔开的整数m和n,表示班里有m行n列(1<=m,n<=50)。
接下来的m行是一个m*n的矩阵,矩阵中第i行j列的整数表示坐在第i行j列的学生的好心程度。每行的n个整数之间用空格隔开。

【输出】
输出文件message.out共一行,包含一个整数,表示来回两条路上参与传递纸条的学生的好心程度之和的最大值。

【输入输出样例】
message.in message.out
3 3
0 3 9
2 8 5
5 7 0 34

【限制】
30%的数据满足:1<=m,n<=10
100%的数据满足:1<=m,n<=50

此题用dp的做法,因为从右下往左上可以等价看为从右上往左下脚走,两种是相同的,那么用四维的数组保存状态
dp【i】【j】【k】【p】表示为走到两个点(i,j)(k,p)所可以拿到的最大的好感度那么
状态转移方程可以轻松的写出来详情见代码

/********************
测试通过 Accepted

总耗时: 113 ms
0 / 0 数据通过测试.
运行结果
测试点#message1.in  结果:AC    内存使用量:  256kB     时间使用量:  0ms     
测试点#message10.in  结果:AC    内存使用量:  23532kB     时间使用量:  30ms     
测试点#message2.in  结果:AC    内存使用量:  256kB     时间使用量:  1ms     
测试点#message3.in  结果:AC    内存使用量:  492kB     时间使用量:  1ms     
测试点#message4.in  结果:AC    内存使用量:  1004kB     时间使用量:  0ms     
测试点#message5.in  结果:AC    内存使用量:  2540kB     时间使用量:  0ms     
测试点#message6.in  结果:AC    内存使用量:  7276kB     时间使用量:  4ms     
测试点#message7.in  结果:AC    内存使用量:  18408kB     时间使用量:  20ms     
测试点#message8.in  结果:AC    内存使用量:  21100kB     时间使用量:  25ms     
测试点#message9.in  结果:AC    内存使用量:  23532kB     时间使用量:  32ms
********************/
#include 
#include 
#include 
#include 
using namespace std;

int mp[51][51];
int dp[51][51][51][51];
int m, n;


int main() {
    scanf( "%d%d", &m, &n );
    for ( int i = 1; i <= m; i++ )
        for ( int j = 1; j <= n; j++ ) scanf( "%d", &mp[i][j] );
    for ( int i = 1; i <= m; i++ )
        for ( int j = 1; j <= n; j++ )
            for ( int k = 1; k <= m; k++ )
                for ( int p = 1; p <= n; p++ ) {
                if ( i == k && j == p && i != m && j != n && k != m && p != n ) 
                    continue;
                    if ( (i + j) != (k + p) ) continue;
                    int tmp1 = 0;
                    int i1, i2, j1, j2, k1, k2, p1, p2;
                    i1 = i; j1 = j - 1;
                    i2 = i - 1; j2 = j;
                    k1 = k; p1 = p - 1;
                    k2 = k - 1; p2 = p;
                    if ( i1 != k1 || j1 != p1 ) 
                    tmp1 = max( tmp1, dp[i1][j1][k1][p1] );
                    if ( i1 != k2 || j1 != p2 ) 
                    tmp1 = max( tmp1, dp[i1][j1][k2][p2] );
                    if ( i2 != k1 || j1 != p1 ) 
                    tmp1 = max( tmp1, dp[i2][j2][k1][p1] );
                    if ( i2 != k2 || j2 != p2 ) 
                    tmp1 = max( tmp1, dp[i2][j2][k2][p2] );
                    dp[i][j][k][p] = tmp1 + mp[i][j] + mp[k][p];
                }
    printf( "%d\n", dp[m][n][m][n] );
    return 0;
}
  1. 双栈排序
    (twostack.pas/c/cpp)
    【问题描述】
    Tom最近在研究一个有趣的排序问题。如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序。
    操作a
    如果输入序列不为空,将第一个元素压入栈S1
    操作b
    如果栈S1不为空,将S1栈顶元素弹出至输出序列
    操作c
    如果输入序列不为空,将第一个元素压入栈S2
    操作d
    如果栈S2不为空,将S2栈顶元素弹出至输出序列
    如果一个1~n的排列P可以通过一系列操作使得输出序列为1, 2,…,(n-1), n,Tom就称P是一个“可双栈排序排列”。例如(1, 3, 2, 4)就是一个“可双栈排序序列”,而(2, 3, 4, 1)不是。下图描述了一个将(1, 3, 2, 4)排序
    【输入输出样例1】
    twostack.in twostack.out
    4
    1 3 2 4 a b a a b b a b
    【输入输出样例2】
    twostack.in twostack.out
    4
    2 3 4 1 0
    【输入输出样例3】
    twostack.in twostack.out
    3
    2 3 1 a c a b b d

用二分图匹配
对于Stack如果要从小到大输出有一个性质就是
i小于j ,p[i] 和p [j]代表进stack的元素大小
i、j表示进Stack的顺序,如果存在k>j且p[k]小于a[i]那么无论如何i、j都无法按规则输出。
所以我们找到这样的i、j然后把他们两个之间连一条边,表示其两个不能在一个stack中,那么到最后如果可以用两个stack输出就必然为一个二分图,因为如果一个集合里两点有边则不成立。
对于如何找这样两个i、j我们设一个后缀最小数组f[i]表示从i以后的连续数列的最小值。
在建成图后我们进行染色,将其中一个染色为1,一个染色为2,那么最后我们进行模拟就可以了按照a、b、c、d的优先进行模拟
(笔者一开始未想到如何正解,所以快速编了一个模拟可以过3个点)

/********************
测试通过 Accepted

总耗时: 5 ms
0 / 0 数据通过测试.
运行结果
测试点#twostack1.in  结果:AC    内存使用量:  256kB     时间使用量:  0ms     
测试点#twostack10.in  结果:AC    内存使用量:  256kB     时间使用量:  0ms     
测试点#twostack2.in  结果:AC    内存使用量:  256kB     时间使用量:  1ms     
测试点#twostack3.in  结果:AC    内存使用量:  128kB     时间使用量:  1ms     
测试点#twostack4.in  结果:AC    内存使用量:  256kB     时间使用量:  0ms     
测试点#twostack5.in  结果:AC    内存使用量:  256kB     时间使用量:  1ms     
测试点#twostack6.in  结果:AC    内存使用量:  256kB     时间使用量:  0ms     
测试点#twostack7.in  结果:AC    内存使用量:  256kB     时间使用量:  0ms     
测试点#twostack8.in  结果:AC    内存使用量:  128kB     时间使用量:  1ms     
测试点#twostack9.in  结果:AC    内存使用量:  128kB     时间使用量:  1ms 
********************/
#include 
#include 
#include 
using namespace std;

struct Edge{
    int v, next;
};
Edge e[2005];
int head[1005], num, n, aa[1005], f[1005], col[1005], sa[1005], sb[1005], ta, tb, pos = 1;
void adde( int i, int j ) {
    e[++num].v = j;
    e[num].next = head[i];
    head[i] = num;
    e[++num].v = i;
    e[num].next = head[j];
    head[j] = num;
}
void dfs( int u, int c ) {
    col[u] = c;
    for ( int i = head[u]; i; i = e[i].next ) {
        int v = e[i].v;
        if ( col[v] == c ) {
            printf("0\n");
            exit(0);
        }
        if ( !col[v] ) dfs(v, 3 - c);
    }
}
int main() {
    scanf( "%d", &n );
    for ( int i = 1; i <= n; i++ ) scanf( "%d", &aa[i] );
    f[n + 1] = 0x3f3f3f3f;
    for ( int i = n; i >= 1; i-- ) f[i] = min( f[i + 1], aa[i] ); 
    for ( int i = 1; i < n; i++ )
        for ( int j = i + 1; j <= n; j++ ) if ( aa[i] < aa[j] && f[j + 1] < aa[i] ) adde(i, j);
    for ( int i = 1; i <= n; i++ ) if ( !col[i] ) dfs(i, 1);
    for ( int i = 1; i <= n; i++ ) {
        if ( col[i] == 1 ) {
            sa[++ta] = aa[i];
            printf("a ");
        } else {
            sb[++tb] = aa[i];
            printf("c ");
        }
        while ( ta && sa[ta] == pos || tb && sb[tb] == pos ) {
            if ( ta && sa[ta] == pos ) {
                ta--;
                printf("b ");
            }
            if ( tb && sb[tb] == pos ) {
                tb--;
                printf("d ");
            }
            pos++;
        }
    }
    return 0;
}

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