ACM算法群赛

题目链接:
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=104302#overview
Problem A

Description
有两堆石子,数量任意,可以不同。游戏开始由两个人轮流取石子。游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子;二是可以在两堆中同时取走相同数量的石子。最后把石子全部取完者为胜者。现在给出初始的两堆石子的数目,如果轮到你先取,假设双方都采取最好的策略,问最后你是胜者还是败者。

Input
输入包含若干行,表示若干种石子的初始情况,其中每一行包含两个非负整数a和b,表示两堆石子的数目,a和b都不大于1,000,000,000。

Output
输出对应也有若干行,每行包含一个数字10,如果最后你是胜者,则为1,反之,则为0。

Sample Input

2 1
8 4
4 7

Sample Output

0
1
0

此题为一道博弈题(威佐夫博弈)
当x = i*(sqrt(5)+1)/2, y = x+i时为必输局。

#include <stdio.h>
#include <math.h>
#define LL long long
int main ( )
//威佐夫博弈,当x = i*(sqrt(5)+1)/2  y = x+i时为必输局
{
    LL a, b;
    while ( ~ scanf ( "%I64d%I64d", &a, &b ) )
    {
        if ( a > b )
        {
            LL t = a;
            a = b;
            b = t;
        }
        LL ans = ( LL )( b-a )*( sqrt ( 5.0 )+1 )/2;
        printf ( "%d\n", ans == a ? 0 : 1 );
    }
}

Problem B

Description

Factorial of an integer is defined by the following function

f(0) = 1

f(n) = f(n - 1) * n, if(n > 0)

So, factorial of 5 is 120. But in different bases, the factorial may be different. For example, factorial of 5 in base 8 is 170.

In this problem, you have to find the number of digit(s) of the factorial of an integer in a certain base.

Input

Input starts with an integer T (≤ 50000), denoting the number of test cases.

Each case begins with two integers n (0 ≤ n ≤ 106) and base (2 ≤ base ≤ 1000). Both of these integers will be given in decimal.

Output

For each case of input you have to print the case number and the digit(s) of factorial n in the given base.

Sample Input

5

5 10

8 10

22 3

1000000 2

0 100

Sample Output

Case 1: 3
Case 2: 5
Case 3: 45
Case 4: 18488885
Case 5: 1

题意:将n!化成m进制的位数。
分析:
求位数实际就是求出m的多少次方,所以可以用取对数的方法求,
例如:bit10(5!)= log10(1*2*3*4*5) = 3
那么求m进制,就只要将10改成m就行,
另外一个性质是:
log a(b) = log10 a/log 10 b
那么就可以合并得到(lg1+lg2+…+lgn)/lgm

#include <stdio.h>
#include <math.h>
#define eps 1e-9
const int maxn = 1000005;
double ans[maxn];
int main ( )
{
    int T, n, b, cas = 1;
    ans[0] = 0;
    for ( int i = 1; i < maxn; i ++ )
    //将所有log10(1*...*i)的值先算出来
        ans[i] = ans[i-1]+log ( i );
    scanf ( "%d", &T );
    while ( T -- )
    {
        scanf ( "%d%d", &n, &b );
        printf ( "Case %d: ", cas ++ );
        if ( n == 0 )   //0!为1
        {
            printf ( "1\n" );
            continue ;
        }
        double t = ans[n]/log ( b );
        long long val = ( long long )t;
        if ( t-val >= eps ) //进位,用1e-5过不了,所以用了1e-9
            val ++;
        printf ( "%lld\n", val );
    }
    return 0;
}

Problem C
C题就是枚举起点和终点,去异或值最大的就行,没什么好讲的。

#include <stdio.h>
#define LL long long
const int maxn = 105;
LL a[maxn];
int main ( )
{
    int n;
    LL ans = 0;
    scanf ( "%d", &n );
    for ( int i = 0; i < n; i ++ )
        scanf ( "%lld", &a[i] );
    for ( int i = 0; i < n; i ++ )
    {
        for ( int j = i; j < n; j ++ )
        {
            LL xr = 0;
            for ( int k = i; k <= j; k ++ )
                xr ^= a[k];
            if ( ans < xr )
                ans = xr;
        }
    }
    printf ( "%lld", ans );
    return 0;
}

Problem D

Description

Igor has fallen in love with Tanya. Now Igor wants to show his feelings and write a number on the fence opposite to Tanya's house. Igor thinks that the larger the number is, the more chance to win Tanya's heart he has.

Unfortunately, Igor could only get v liters of paint. He did the math and concluded that digit d requires ad liters of paint. Besides, Igor heard that Tanya doesn't like zeroes. That's why Igor won't use them in his number.

Help Igor find the maximum number he can write on the fence.

Input

The first line contains a positive integer v(0 ≤ v ≤ 106). The second line contains nine positive integers a1, a2, ..., a9(1 ≤ ai ≤ 105).

Output

Print the maximum number Igor can write on the fence. If he has too little paint for any digit (so, he cannot write anything), print -1.

Sample Input
Input

5
5 4 3 2 1 2 3 4 5

Output

55555

Input

2
9 11 1 12 5 8 9 10 6

Output

33

Input

0
1 1 1 1 1 1 1 1 1

Output

-1

题意:你有数字1-9,每次刷出某个数字需要消耗d[i]升油漆,你总共有v升油漆,你需要找出能刷出的数字最大为多少,一个数字都不能刷出就输出-1.
分析:
这道题我开始一直找位数最多的,其实这样是不完全对的,因为能得到的数字的位数是已经确定了的,你需要贪心高位的数字让其变大,所以找所有数字中需要油漆最少的,那样位数肯定是最大的m,但是有可能会有剩余,那么就可以利用这些剩余油漆来使高位变大(此题浪费一个多小时)。

#include <stdio.h>
#include <string.h>
#define INF 0x7fffffff
const int maxn = 15, N = 1000005;
int d[maxn];
char str[N];
int main ( )
{
    int v;
    scanf ( "%d", &v );
    for ( int i = 1; i < 10; i ++ )
        scanf ( "%d", &d[i] );
    int m = INF, ansi;
    for ( int i = 1; i < 10; i ++ )
    {
        if ( m >= d[i] )    //找到需要油漆最少的,且数字最大的
        {
            m = d[i];
            ansi = i;
        }
    }
    if ( v/m == 0 ) //一个都刷不了
    {
        printf ( "-1" );
        return 0;
    }
    strcpy ( str, "" );
    int cnt = 0, mod = v%d[ansi];   //余数
    m = v/m;    //能刷ansi此数字的个数
    while ( mod > 0 )
    {
        int flag = 0;
        for ( int i = 9; i > ansi; i -- )   //从后往前找,尽量让高位大
            if ( mod+d[ansi] >= d[i] )
            {
                flag = 1;   //标记找到数字
                mod += d[ansi]-d[i];    //余数缩小
                m --;   //取ansi个数减少,不能省
                str[cnt ++] = i+'0';
                break ;
            }
        if ( flag == 0 )
            break ;
    }
    str[cnt] = '\0';
    //printf ( "%d\n", m );
    printf ( "%s", str );
    for ( int i = 0; i < m; i ++ )
        printf ( "%d", ansi );  //还要取m个ansi
    return 0;
}
/*
9
2 3 5 5 5 5 5 5 5
*/

Problem E

Description
Given an N*N(N<=1000)chessboard where you want to place chess knights.
On this chessboard you have to apply M(M<=100000) operations:

Input
The first line contains a single integer T, the number of test cases.
For each case,
The first line contains integer N, M.
The next M lines contain the operation in following form.
C a b x: place chess knight on cell(a,b), the value of the knight is x. (1<=a,b<=n, 1<=x<=100000)
It grants that cell(a,b) has no knight before the operation.
Q a b: answer the maximum value of knight which is connected with knight(a,b), include itself.
If cell (a,b)has no knight, just answer -1. A knight is directly connected with the knight on the left, 
right,  up  and  down.  Two  knights  are  connected  if  they  have  been  directly  connected  or 
interconnected through some other connected knights.
The initial chessboard is empty.

Output
For each question, output the answer in one line.

Sample Input

1
3 7
C 2 2 1
Q 2 2
C 1 2 2
Q 2 2
C 3 3 3
Q 3 3
Q 1 1

Sample Output

1
2
3
-1

题意:
有两种操作:C a b c将cell(a,b)这个格子的值更新为c,只会更新一次,
Q a b表示查询此格子所在连通块的最大值。
注意连通块是与上下左右相连的,我开始将其相成图,这跟图是不一样的,图是相连的是连通的。

#include <stdio.h>
#include <string.h>
const int maxn = 1005*1005;
int father[maxn];
int mx[maxn], vis[maxn], n;
int dx[] = { 1, 0, -1, 0 }, dy[] = { 0, 1, 0, -1 };
void init ( int m ) //初始化
{
    for ( int i = 1; i <= m; i ++ )
        father[i] = i, vis[i] = mx[i] = 0;
}
int find ( int x )
{
    int r = x;
    while ( r != father[r] )
        r = father[r];
    int i = x, j;
    while ( i != r )
    {
        j = father[i];
        father[i] = r;
        i = j;
    }
    return r;
}
void merge ( int x, int y )
{
    int fx = find ( x ), fy = find ( y );
    if ( fx != fy )
    {
        father[fx] = fy;
        if ( mx[fy] < mx[fx] )  //更新父节点的最大值
            mx[fy] = mx[fx];
    }
}
int check ( int x, int y )
{
    return x <= 0 || x > n || y <= 0 || y > n;
}
int main ( )
{
    int T, m, a, b, c, x, y;
    char op[2];
    scanf ( "%d", &T );
    while ( T -- )
    {
        scanf ( "%d%d", &n, &m );
        init ( n*( n+2 ) ); //初始化的时候需要大一些
        while ( m -- )
        {
            scanf ( "%s", op );
            if ( op[0] == 'C' )
            {
                scanf ( "%d%d%d", &a, &b, &c );
                x = a*n+b;  //n可能为0,所以不能用n-1
                vis[x] = 1;
                mx[x] = c;
                for ( int i = 0; i < 4; i ++ )  //注意只有相邻才是连通的
                {
                    int na = dx[i]+a, nb = dy[i]+b;
                    if ( check ( na, nb ) ) //检查边界
                        continue ;
                    y = na*n+nb;
                    if ( vis[y] == 0 )
                        continue ;
                    merge ( x, y );
                }
            }
            else
            {
                scanf ( "%d%d", &a, &b );
                x = a*n+b;
                if ( vis[x] == 0  ) //此点没赋值过
                    printf ( "-1\n" );
                else
                    printf ( "%d\n", mx[ find ( x ) ] );
                //查找此连通块的最大值
            }
        }
    }
    return 0;
}
时间复杂度(渐近时间复杂度的严格定义,NP问题,时间复杂度的分析方法,主定理)   排序算法(平方排序算法的应用,Shell排序,快速排序,归并排序,时间复杂度下界,三种线性时间排  序,外部排序)   数论(整除,集合论,关系,素数,进位制,辗转相除,扩展的辗转相除,同余运算,解线性同余方程,中国剩余定理) 指针(链表,搜索判重,邻接表,开散列,二叉树的表示,多叉树的表示) 按位运算(and,or,xor,shl,shr,一些应用) 图论(图论模型的建立,平面图,欧拉公式与五色定理,求强连通分量,求割点和桥,欧拉回路,AOV问题,AOE问题,最小生成树的三种算法,最短路的三种算法,标号法,差分约束系统,验证二分图,Konig定理,匈牙利算法,KM算法,稳定婚姻系统,最大流算法,最小割最大流定理,最小费用最大流算法) 计算几何(平面解几及其应用,向量,点积及其应用,叉积及其应用,半平面相交,求点集的凸包,最近点对问题,凸多边形的交,离散化与扫描) 数据结构(广度优先搜索,验证括号匹配,表达式计算,递归的编译,Hash表,分段Hash,并查集,Tarjan算法,二叉堆,左偏树,二斜堆,二项堆,二叉查找树,红黑树,AVL平衡树,Treap,Splay,静态二叉查找树,2-d树,线段树,二维线段树,矩形树,Trie树,块状链表) 组合数学(排列与组合,鸽笼原理,容斥原理,递推,Fibonacci数列,Catalan数列,Stirling数,差分序列,生成函数,置换,Polya原理) 概率论(简单概率,条件概率,Bayes定理,期望值) 矩阵(矩阵的概念和运算,二分求解线性递推方程,多米诺骨牌棋盘覆盖方案数,高斯消元) 字符串处理(KMP,后缀树,有限状态自动机,Huffman编码,简单密码学) 动态规划(单调队列,凸完全单调性,树型动规,多叉转二叉,状态压缩类动规,四边形不等式) 博奕论(Nim取子游戏,博弈树,Shannon开关游戏) 搜索(A*,ID,IDA*,随机调整,遗传算法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值