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;
}
發佈了20 篇原創文章 · 獲贊 21 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章