Codeforces Round #228 div1前三題

果7發表於2014-02-05

A題:

A. Fox and Box Accumulation
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

Fox Ciel has n boxes in her room. They have the same size and weight, but they might have different strength. The i-th box can hold at most xi boxes on its top (we'll call xi the strength of the box).

Since all the boxes have the same size, Ciel cannot put more than one box directly on the top of some box. For example, imagine Ciel has three boxes: the first has strength 2, the second has strength 1 and the third has strength 1. She cannot put the second and the third box simultaneously directly on the top of the first one. But she can put the second box directly on the top of the first one, and then the third box directly on the top of the second one. We will call such a construction of boxes a pile.

Fox Ciel wants to construct piles from all the boxes. Each pile will contain some boxes from top to bottom, and there cannot be more thanxi boxes on the top of i-th box. What is the minimal number of piles she needs to construct?

Input

The first line contains an integer n (1 ≤ n ≤ 100). The next line contains n integers x1, x2, ..., xn (0 ≤ xi ≤ 100).

Output

Output a single integer — the minimal possible number of piles.

Sample test(s)
input
3
0 0 10
output
2
input
5
0 1 2 3 4
output
1
input
4
0 0 0 0
output
4
input
9
0 1 0 2 0 1 1 2 10
output
3
Note

In example 1, one optimal way is to build 2 piles: the first pile contains boxes 1 and 3 (from top to bottom), the second pile contains only box 2.

In example 2, we can build only 1 pile that contains boxes 1, 2, 3, 4, 5 (from top to bottom).



題目大意:給你一些物品給出每件物品上面最多放多少箱子,然後求解最少放多少堆。

解題思路:可以採取貪心的策略。這題相對來說比較簡單,每次都從可以放最少的箱子數量從上往下放,這樣貪心可以求解。


AC程式碼:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;

int a[102];

int main()
{
    int n,i,x;
    while(cin>>n)
    {
        memset(a,0,sizeof(a));
        for(i=0;i<n;i++)
        {
            cin>>x;
            a[x]++;
        }

        int res=0;
        while(1)
        {
            int flag=0;
            for(i=0;i<=100;i++)
            {
                if(a[i])
                {
                    flag=1;
                    break;
                }
            }

            if(flag==0) break;

            int step=0;
            for(i=0;i<=100;i++)
            {
                if((a[i]>=1&&i==step)||(a[i]==1&&step<i))
                {
                    a[i]--;
                    step++;
                }
                else if(step<i&&a[i]>=2)
                {
                    a[i]--;
                    step++;

                    //cout<<i<<" "<<step<<" dsad"<<endl;
                    //continue;
                    i--;
                }
            }

            //for(i=0;i<=5;i++)
                //cout<<a[i]<<" ";
            //cout<<endl;

            res++;
        }

        cout<<res<<endl;
    }
    return 0;
}

/*
3
0 0 10
5
0 1 2 3 4
4
0 0 0 0
9
0 1 0 2 0 1 1 2 10
7
0 2 2 2 3 4 5
*/

這個題目當時寫的時候很拙計,雖然樣例過了,但是自己隨便寫了組測試資料就過不了,然後就debug了好久。。


B題:
B. Fox and Minimal path
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

Fox Ciel wants to write a task for a programming contest. The task is: "You are given a simple undirected graph with n vertexes. Each its edge has unit length. You should calculate the number of shortest paths between vertex 1 and vertex 2."

Same with some writers, she wants to make an example with some certain output: for example, her birthday or the number of her boyfriend. Can you help her to make a test case with answer equal exactly to k?

Input

The first line contains a single integer k (1 ≤ k ≤ 109).

Output

You should output a graph G with n vertexes (2 ≤ n ≤ 1000). There must be exactly k shortest paths between vertex 1 and vertex 2 of the graph.

The first line must contain an integer n. Then adjacency matrix G with n rows and n columns must follow. Each element of the matrix must be 'N' or 'Y'. If Gij is 'Y', then graph G has a edge connecting vertex i and vertex j. Consider the graph vertexes are numbered from 1 ton.

The graph must be undirected and simple: Gii = 'N' and Gij = Gji must hold. And there must be at least one path between vertex 1 and vertex 2. It's guaranteed that the answer exists. If there multiple correct answers, you can output any of them.

Sample test(s)
input
2
output
4
NNYY
NNYY
YYNN
YYNN
input
9
output
8
NNYYYNNN
NNNNNYYY
YNNNNYYY
YNNNNYYY
YNNNNYYY
NYYYYNNN
NYYYYNNN
NYYYYNNN
input
1
output
2
NY
YN
Note

In first example, there are 2 shortest paths: 1-3-2 and 1-4-2.

In second example, there are 9 shortest paths: 1-3-6-2, 1-3-7-2, 1-3-8-2, 1-4-6-2, 1-4-7-2, 1-4-8-2, 1-5-6-2, 1-5-7-2, 1-5-8-2.


題目大意:讓你構造一張圖,使得結點1到結點2最短路走的方法有n種,當然1<=n<=10^9,當時突然靈光一閃就是素數分解,然後就開始寫了,不過大於1000的素數是不可以的,因為要求最多隻能用1000個點,然後題目有一句話說了:不會給沒有答案的n。然後我就抱著慶幸的態度交了。不過最後被hack了。直到最後也沒能想通。

解題思路:不過在晚上的時候突然想到了,覺得素數分解不了的話,還可以按照權基數的思想呢,然後早上突然就覺得可以試一下二進位制,看了下別人的思路,然後就覺得自己的構造捉急。就是二進位制的思想。

每次
1
3 4 5
6 7 8
9 10 11
每次都讓3和6,7連著,4和6,7連著.,6連線9,10,7連線9,10.....1連線5,5連線8,8連線11 ,如果到5結點的時候權是1,那麼就讓5往左邊6,7連線即可,如果權是0,那麼就不管,最後讓最後三個點裡面的最左邊兩個點都連著2,如果k&1==1,那麼最後三個點裡面最後一個點也連線2.就是這個思想,具體見程式碼。

由於k最大為10^9<2^30,那麼只需要1+90+1個點就可以搞定。


AC程式碼:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;

int mp[100][105];

int main()
{
    int k;
    int i,j;
    while(cin>>k)
    {
        memset(mp,0,sizeof(mp));
        mp[1][5]=1;
        if(k&(1<<30))
        {
            mp[1][3]=1;
            mp[1][4]=1;
        }

        j=3;
        for(i=29;i>=1;i--)
        {
            mp[j][j+3]=1,mp[j][j+4]=1;
            mp[j+1][j+3]=1,mp[j+1][j+4]=1;
            mp[j+2][j+5]=1;
            if(k&(1<<i))
            {
                mp[j+2][j+3]=1;
                mp[j+2][j+4]=1;
            }
            j+=3;
        }

        mp[90][2]=1,mp[91][2]=1;
        if(k&1) mp[92][2]=1;

        cout<<92<<endl;
        for(i=1;i<=92;i++)
        {
            for(j=1;j<=92;j++)
            {
                if(mp[i][j]||mp[j][i]) cout<<"Y";
                else cout<<"N";
            }
            cout<<endl;
        }
    }
    return 0;
}


C題:
C. Fox and Card Game
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

Fox Ciel is playing a card game with her friend Fox Jiro. There are n piles of cards on the table. And there is a positive integer on each card.

The players take turns and Ciel takes the first turn. In Ciel's turn she takes a card from the top of any non-empty pile, and in Jiro's turn he takes a card from the bottom of any non-empty pile. Each player wants to maximize the total sum of the cards he took. The game ends when all piles become empty.

Suppose Ciel and Jiro play optimally, what is the score of the game?

Input

The first line contain an integer n (1 ≤ n ≤ 100). Each of the next n lines contains a description of the pile: the first integer in the line issi (1 ≤ si ≤ 100) — the number of cards in the i-th pile; then follow si positive integers c1c2, ..., ck, ..., csi (1 ≤ ck ≤ 1000) — the sequence of the numbers on the cards listed from top of the current pile to bottom of the pile.

Output

Print two integers: the sum of Ciel's cards and the sum of Jiro's cards if they play optimally.

Sample test(s)
input
2
1 100
2 1 10
output
101 10
input
1
9 2 8 6 5 9 4 7 1 3
output
30 15
input
3
3 1 3 2
3 5 4 6
2 8 7
output
18 18
input
3
3 1000 1000 1000
6 1000 1000 1000 1000 1000 1000
5 1000 1000 1000 1000 1000
output
7000 7000
Note

In the first example, Ciel will take the cards with number 100 and 1, Jiro will take the card with number 10.

In the second example, Ciel will take cards with numbers 2, 8, 6, 5, 9 and Jiro will take cards with numbers 4, 7, 1, 3.


題目大意:看起來是個博弈題目,A,B分別拿物品,總共有n堆物品,每堆物品有s[i]個,從上面到下面分別放,每個物品各自的價值。A先拿物品,不過他每次只能選擇從某一堆最上面拿出物品,而B每次只能選擇從某一堆最下面拿出物品。A,B輪流拿物品,A,B都是最優選擇使得總價值最大。問你 A,B最終得分。

解題思路:我想的思路開始覺得是dp,但是覺得無從下手。後來就放棄了,看了下題解,原來貪心就可以搞定。
然後我就舉了個例子。
3
3 5 6 7
3 1 2 3
4 4 3 2 1
按照這樣,如果A,B每次都拿最大的,結果不一定最優。
A拿的分為:5 6 4 3 2
B拿的分為:7 3 2 1 1
但是實際上B可以先不拿第二堆的3,因為3在最下面,可以先拿第三堆得1,然後就可以拿第二堆的2了。

實際上的得分為:
A拿的分為:5 6 4 3 1
B拿的分為:7 1 2 3 2

通過多找幾輪就會發現,每次一堆的最上面一半是給A了,下面一半是給B了,然後再對中間剩餘的排序即可。因為是博弈,當然每個人的態度都是一樣的,這樣也合情合理,實際證明方法也沒多想。

題目地址:C. Fox and Card Game

AC程式碼:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
using namespace std;

vector <int> mq[105];
int xf[105];

int main()
{
    int n,s,x;
    int i,j;

    int a,b;
    while(cin>>n)
    {
        for(i=1;i<=100;i++)
            mq[i].clear();
        a=0,b=0;

        for(i=1;i<=n;i++)
        {
            cin>>s;
            while(s--)
            {
                cin>>x;
                mq[i].push_back(x);
            }
        }

        int t=0;
        for(i=1;i<=n;i++)
        {
            if(!(mq[i].size()&1))
            {
                for(j=0;j<mq[i].size()/2;j++) a+=mq[i][j];
                for(;j<mq[i].size();j++) b+=mq[i][j];
            }
            else
            {
                for(j=0;j<mq[i].size()/2;j++) a+=mq[i][j];
                xf[t++]=mq[i][j++];
                for(;j<mq[i].size();j++) b+=mq[i][j];
            }
        }

        sort(xf,xf+t);
        int flag=0;
        for(i=t-1;i>=0;i--)
        {
            if(!flag)
            {
                a+=xf[i];
                flag=1;
            }
            else
            {
                b+=xf[i];
                flag=0;
            }
        }

        cout<<a<<" "<<b<<endl;
    }

    return 0;
}

/*
2
1 100
2 1 10

1
9 2 8 6 5 9 4 7 1 3

3
3 1 3 2
3 5 4 6
2 8 7

3
3 1000 1000 1000
6 1000 1000 1000 1000 1000 1000
5 1000 1000 1000 1000 1000
*/


相關文章