2016ACM/ICPC亞洲區大連站現場賽題解報告

此文章可以使用目錄功能喲↑(點擊上方[+])

下午重現了一下大連賽區的比賽,感覺有點神奇,重現時居然改了現場賽的數據範圍,原本過的人數比較多的題結果重現過的變少了,而原本現場賽全場過的人最少的題重現做出的人反而多了一堆,不過還是不影響最水的6題,然而殘酷的現實是6題纔有機會拿銅...(╥╯^╰╥)

鏈接→2016ACM/ICPC亞洲區大連站-重現賽

 Problem 1001 Wrestling Match

Accept: 0    Submit: 0
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)

 Problem Description

Nowadays, at least one wrestling match is held every year in our country. There are a lot of people in the game is "good player”, the rest is "bad player”. Now, Xiao Ming is referee of the wrestling match and he has a list of the matches in his hand. At the same time, he knows some people are good players,some are bad players. He believes that every game is a battle between the good and the bad player. Now he wants to know whether all the people can be divided into "good player" and "bad player". 

 Input

Input contains multiple sets of data.For each set of data,there are four numbers in the first line:N (1 ≤ N≤ 1000)、M(1 ≤M ≤ 10000)、X,Y(X+Y≤N ),in order to show the number of players(numbered 1toN ),the number of matches,the number of known "good players" and the number of known "bad players".In the next M lines,Each line has two numbersa, b(a≠b) ,said there is a game between a and b .The next line has X different numbers.Each number is known as a "good player" number.The last line contains Y different numbers.Each number represents a known "bad player" number.Data guarantees there will not be a player number is a good player and also a bad player.

 Output

If all the people can be divided into "good players" and "bad players”, output "YES", otherwise output "NO".

 Sample Input

5 4 0 0
1 3
1 4
3 5
4 5
5 4 1 0
1 3
1 4
3 5
4 5
2

 Sample Output

NO
YES

 Problem Idea

解題思路:

【題意】

這個題目意思,感覺還是存疑的( ̄へ ̄),我只能以本人過了此題的想法來解釋

N個選手,M場摔跤比賽,已知N個選手中有X個選手是"good player",Y個選手是"bad player"

問是否可以將N個選手劃分成"good player"和"bad player"兩個陣營,使得每場摔跤比賽的兩位選手必定是一位來自"good player",一位來自"bad player"

【類型】
搜索(bfs or dfs)
【分析】

有挺多人要求解釋樣例的,因爲不太明白爲啥不告訴2是哪一個陣營就無法劃分陣營了?明明(1,5)和(3,4)也不知道是哪一陣營

但是,我們可以這樣理解一下,即便我不知道(1,5)是屬於"good player"陣營還是屬於"bad player"陣營,他們只能屬於一種陣營

而2是沒有告訴你和其他選手的關係,那麼2可以同屬於兩個陣營,顯然這與題目要求" there will not be a player number is a good player and also a bad player"不符

好了,接下來講做法,首先考慮已經告訴你是哪個陣營的選手A,那麼和A選手比賽的選手B必定對立陣營的,若選手B和選手A是同一陣營,那顯然是無法繼續劃分的,bfs or dfs一下,將已知陣營的選手確定

然後開始處理未知陣營但有比賽的選手,我們完全可以假設其中一方爲"good player",那麼另一方就是"bad player",接着還是bfs or dfs判斷

處理完之後,再遍歷一遍每個選手,看是否還有未知陣營的選手存在即可

重現的時候被自己蠢哭了,(ಥ _ ಥ),因爲每輸入一個已知陣營的選手,我都會去搜索判一次,然後遇到衝突就break了,導致題目還沒有完全輸入就被我結束了,於是WA了好幾發,心疼自己

【時間複雜度&&優化】
O(n)

題目鏈接→HDU 5971 Wrestling Match

 Source Code

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<list>
#include<bitset>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-9
#define LL long long
#define PI acos(-1.0)
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 1005;
const int M = 10005;
const int inf = 1000000007;
const int mod = 1000000007;
struct edge
{
    int v,to;
}e[2*M];
struct node
{
    int u,k;
    node(){}
    node(int _u,int _k):u(_u),k(_k){}
};
int p,v[N],a[M],b[M],h[N];
bool flag;
void add_edge(int u,int v)
{
    e[p].v=v;
    e[p].to=h[u];
    h[u]=p++;
}
void bfs(int u,int k)
{
    queue<node> q;
    int i;
    v[u]=k;
    q.push(node(u,k));
    while(!q.empty())
    {
        u=q.front().u;
        k=q.front().k;
        q.pop();
        for(i=h[u];i+1;i=e[i].to)
        {
            if(v[e[i].v]==k)
            {
                flag=false;
                return ;
            }
            if(!v[e[i].v])
            {
                v[e[i].v]=-k;
                q.push(node(e[i].v,-k));
            }
        }
    }
}
int main()
{
    int n,m,x,y,s,i;
    while(~scanf("%d%d%d%d",&n,&m,&x,&y))
    {
        p=0;
        flag=true;
        memset(v,0,sizeof(v));
        memset(h,-1,sizeof(h));
        for(i=0;i<m;i++)
        {
            scanf("%d%d",&a[i],&b[i]);
            add_edge(a[i],b[i]);
            add_edge(b[i],a[i]);
        }
        for(i=0;i<x;i++)
        {
            scanf("%d",&s);
            if(v[s]==-1)
                flag=false;
            bfs(s,1);
        }
        for(i=0;i<y;i++)
        {
            scanf("%d",&s);
            if(v[s]==1)
                flag=false;
            bfs(s,-1);
        }
        for(i=0;i<m&&flag;i++)
            if(!v[a[i]]&&!v[b[i]])
                bfs(a[i],1);
        for(i=1;i<=n&&flag;i++)
            if(!v[i])
            {
                flag=false;
                break;
            }
        if(flag)
            puts("YES");
        else
            puts("NO");
    }
    return 0;
}

 Problem 1004 A Simple Math Problem

Accept: 0    Submit: 0
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)

 Problem Description

Given two positive integers a and b,find suitable X and Y to meet the conditions: 

 X+Y=a 

 Least Common Multiple (X, Y) =b

 Input

Input includes multiple sets of test data.Each test data occupies one line,including two positive integers a(1≤a≤2*10^4),b(1≤b≤10^9),and their meanings are shown in the description.Contains most of the 12W test cases.

 Output

For each set of input data,output a line of two integers,representing X, Y.If you cannot find such X and Y,output one line of "No Solution"(without quotation).

 Sample Input

6 8
798 10780

 Sample Output

No Solution
308 490

 Problem Idea

解題思路:

【題意】

給你兩個整數a和b

求X和Y,滿足X+Y=a,且LCM(X,Y)=b [LCM(X,Y)表示X和Y的最小公倍數]

若不存在,輸出"No Solution"

否則輸出X最小的解

【類型】
數學推導題
【分析】

現場賽的時候,咋看一眼感覺是水題啊,a的範圍才10^4,那我枚舉一下X和Y,然後判斷它們的最小公倍數是不是b不就完事了?

但看做的人並不多,又仔細看了下題,發現題目組數有點多,12萬,好吧,放棄暴力枚舉

首先,學過最小公倍數的我們知道,兩數之積等於兩數的最大公約數乘最小公倍數,用式子表示如下

X*Y=LCM(X,Y)*GCD(X,Y)

於是,我們不妨假設GCD(X,Y)=k,那麼我們可以知道



假設X≥Y,則


這個方程組還是好解的

無解的情況有如下三種(滿足任意一種都是無解):


【時間複雜度&&優化】
O(1)

題目鏈接→HDU 5974 A Simple Math Problem

 Source Code

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<list>
#include<bitset>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-9
#define LL long long
#define PI acos(-1.0)
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 1005;
const int M = 10005;
const int inf = 1000000007;
const int mod = 1000000007;
__int64 gcd(__int64 a,__int64 b)
{
    if(a%b)
        return gcd(b,a%b);
    return b;
}
int main()
{
    __int64 a,b,k,d,X,Y,s;
    while(~scanf("%I64d%I64d",&a,&b))
    {
        k=gcd(a,b);
        d=a*a-4*k*b;
        if(d<0)
        {
            puts("No Solution");
            continue;
        }
        s=(__int64)sqrt(1.0*d);
        if(s*s!=d||(s+a)%2)
        {
            puts("No Solution");
            continue;
        }
        X=(s+a)/2;
        Y=a-X;
        if(X>Y)
            swap(X,Y);
        printf("%I64d %I64d\n",X,Y);

    }
    return 0;
}

 Problem 1006 Detachment

Accept: 0    Submit: 0
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)

 Problem Description

In a highly developed alien society, the habitats are almost infinite dimensional space.

In the history of this planet,there is an old puzzle.

You have a line segment with x units’ length representing one dimension.The line segment can be split into a number of small line segments: a1,a2, … (x= a1+a2+…) assigned to different dimensions. And then, the multidimensional space has been established. Now there are two requirements for this space: 

1.Two different small line segments cannot be equal ( ai≠aj when i≠j).

2.Make this multidimensional space size s as large as possible (s= a1∗a2*...).Note that it allows to keep one dimension.That's to say, the number of ai can be only one.

Now can you solve this question and find the maximum size of the space?(For the final number is too large,your answer will be modulo 10^9+7)

 Input

The first line is an integer T,meaning the number of test cases.

Then T lines follow. Each line contains one integer x.

1≤T≤10^6, 1≤x≤10^9

 Output

Maximum s you can get modulo 10^9+7. Note that we wants to be greatest product before modulo 10^9+7.

 Sample Input

1
4

 Sample Output

4

 Problem Idea

解題思路:

【題意】

給定一個自然數x,讓你給出一種拆分方式x=a1+a2+...(ai≠aj),使得每個小部分的乘積s=a1*a2*...最大

【類型】
貪心構造
【分析】

此題關鍵在於得出如何能使乘積s最大

按照以往經驗,必然是取一段連續自然數能夠使得乘積最大,而這段連續自然數可從2開始(爲啥不從1開始?從1開始還不如將這個1給這段連續自然數的最後一個數),於是我們可以得到形如2+3+4+...+k(k=2,3,...)的式子,而x是10^9內的任意整數,我們不可能恰好能夠湊成連續自然數之和,可能會多出△x

而這個△x的值,我可以保證它的範圍爲0≤△x≤k,相信大於等於0還是好理解的,爲什麼會小於等於k呢?因爲當它大於k時,原式不是可以增加一項?即2+3+4+...+k+(k+1)

那麼多出來的△x怎麼處理呢?顯然是從後往前均攤給連續自然數中的(k-1)個數,爲啥從後往前?因爲若我們從前往後,總是會使連續自然數重複,不好處理

於是,在我們分配完△x之後,我們大致會得到下述兩種式子:

①2*3*...*(i-1)*(i+1)*...*k*(k+1)

②3*4*...*i*(i+1)*...*k*(k+2)

顯然,我們要計算此結果,可以藉助階乘,而階乘中缺失的項,我們除掉就可以了,那麼便會涉及除法取模,顯然需要用到乘法逆元

做法講解完畢,以下是爲什麼連續段乘積最大的大概證明:


【時間複雜度&&優化】
O(logn)

題目鏈接→HDU 5976 Detachment

 Source Code

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<list>
#include<bitset>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-9
#define LL long long
#define PI acos(-1.0)
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 45000;
const int M = 10005;
const int inf = 1000000007;
const int mod = 1000000007;
__int64 inv[N]={0,1};//逆元篩
__int64 f[N]={1,1};//階乘
int main()
{
    int t,i,x,l,r,mid,k;
    __int64 ans;
    for(i=2;i<N;i++)
    {
        inv[i]=inv[mod%i]*(mod-mod/i)%mod;
        f[i]=(f[i-1]*i)%mod;
    }
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&x);
        if(x<=1)
        {
            printf("%d\n",x);
            continue;
        }
        l=k=2,r=N;
        while(l<=r)
        {
            mid=(l+r)/2;
            if((mid+2)*(mid-1)/2<=x)
                l=mid+1,k=max(k,mid);
            else
                r=mid-1;
        }
        //printf("%d\n",k);
        x-=(k+2)*(k-1)/2;
        if(x==k)//3*4*...*(k-1)*k*(k+2)
            ans=(f[k]*inv[2])%mod*(k+2)%mod;
        else if(x==0)
            ans=f[k];
        else
            ans=(f[k+1]*inv[k-x+1])%mod;
        printf("%I64d\n",ans);
    }
    return 0;
}

 Problem 1008 To begin or not to begin

Accept: 0    Submit: 0
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)

 Problem Description

A box contains black balls and a single red ball. Alice and Bob draw balls from this box without replacement, alternating after each draws until the red ball is drawn. The game is won by the player who happens to draw the single red ball. Bob is a gentleman and offers Alice the choice of whether she wants to start or not. Alice has a hunch that she might be better off if she starts; after all, she might succeed in the first draw. On the other hand, if her first draw yields a black ball, then Bob’s chances to draw the red ball in his first draw are increased, because then one black ball is already removed from the box. How should Alice decide in order to maximize her probability of winning? Help Alice with decision.

 Input

Multiple test cases (number of test cases≤50), process till end of input.

For each case, a positive integer k (1≤k≤10^5) is given on a single line.

 Output

For each case, output:

1, if the player who starts drawing has an advantage

2, if the player who starts drawing has a disadvantage

0, if Alice's and Bob's chances are equal, no matter who starts drawing

on a single line.

 Sample Input

1
2

 Sample Output

0
1

 Problem Idea

解題思路:

【題意】

箱子裏有1個紅球和k個黑球

Alice和Bob輪流不放回地從箱子裏隨機取出一個球

當某人取到紅球時獲得勝利,遊戲結束

問先手是否獲勝機率更大,機率更大,輸出"1";機率更小,輸出"2";機率相等,輸出"0"

【類型】
概率水題
【分析】

此題關鍵還是要多嘗試,手動計算一下

當k=1時,一個紅球和一個黑球,先手獲勝的概率P爲


當k=2時,一個紅球和兩個黑球,先手獲勝的概率P爲


當k=3時,一個紅球和三個黑球,先手獲勝的概率P爲


故,當k時,先手獲勝的概率P爲


那我只需判斷兩者大小關係即可

【時間複雜度&&優化】
O(1)

題目鏈接→HDU 5978 To begin or not to begin

 Source Code

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<list>
#include<bitset>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-9
#define LL long long
#define PI acos(-1.0)
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 5005;
const int M = 100005;
const int inf = 1000000007;
const int mod = 1000000007;
const int MAXN = 100005;
int main()
{
    int k,p;
    while(~scanf("%d",&k))
    {
        p=k/2+1;
        if(p>k+1-p)
            puts("1");
        else if(p<k+1-p)
            puts("2");
        else
            puts("0");
    }
    return 0;
}

 Problem 1009 Convex

Accept: 0    Submit: 0
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)

 Problem Description

We have a special convex that all points have the same distance to origin point.
As you know we can get N segments after linking the origin point and the points on the convex. We can also get N angles between each pair of the neighbor segments.

Now give you the data about the angle, please calculate the area of the convex

 Input

There are multiple test cases.

The first line contains two integer N and D indicating the number of the points and their distance to origin. (3 <= N <= 10, 1 <= D <= 10)

The next lines contain N integers indicating the angles. The sum of the N numbers is always 360.

 Output

For each test case output one float numbers indicating the area of the convex. The printed values should have 3 digits after the decimal point.

 Sample Input

4 1
90 90 90 90
6 1
60 60 60 60 60 60

 Sample Output

2.000
2.598

 Problem Idea

解題思路:

【題意】

二維座標中有N個點,它們到原點的距離均爲D

將這N個點分別與原點相連,現在告訴你任意相鄰兩條線段的夾角爲θi,求這N個點構成的凸包面積(N邊形面積)

【類型】
三角形面積水題
【分析】

題目大概樣子如下


由圖可知,n邊形的面積可以拆分成n個三角形面積之和

而已知每個三角形的兩邊及兩邊夾角,我們可以通過三角形面積公式算出每個三角形的面積,相加之和便是最終的n邊形面積


由於math.h頭文件中封裝的sin運算是以弧度制來計算的,而題目所給的是角度制,故我們還需多一步角度轉弧度

【時間複雜度&&優化】
O(1)

題目鏈接→HDU 5979 Convex

 Source Code

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<list>
#include<bitset>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-9
#define LL long long
#define PI acos(-1.0)
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 5005;
const int M = 100005;
const int inf = 1000000007;
const int mod = 1000000007;
const int MAXN = 100005;
int main()
{
    int n,d,i,x;
    double ans;
    while(~scanf("%d%d",&n,&d))
    {
        ans=0;
        for(i=0;i<n;i++)
        {
            scanf("%d",&x);
            ans+=d*d*sin(PI*x/180)/2;
        }
        printf("%.3f\n",ans);
    }
    return 0;
}

 Problem 1010 Find Small A

Accept: 0    Submit: 0
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)

 Problem Description

As is known to all,the ASCII of character 'a' is 97. Now,find out how many character 'a' in a group of given numbers. Please note that the numbers here are given by 32 bits’ integers in the computer.That means,1digit represents 4 characters(one character is represented by 8 bits’ binary digits).

 Input

The input contains a set of test data.The first number is one positive integer N (1≤N≤100),and then N positive integersai (1≤ ai≤2^32 - 1) follow

 Output

Output one line,including an integer representing the number of 'a' in the group of given numbers.

 Sample Input

3
97 24929 100

 Sample Output

3

 Problem Idea

解題思路:

【題意】

給你n個32位整數,每個整數可以表示成4個字符(因爲一個字符在計算機中佔8位),問n個整數共包含多少個字符'a'

【類型】
簽到題
【分析】

由於一個字符佔二進制8位,所以每個整數相當於轉化爲2^8=256進制數

那麼將32位整數循環對256取模,看是不是97(字符'a')即可

其中需要注意的一點是,2^32-1已經超過了int型的範圍,故須定義成 __int64 或 long long

int型的最大值爲2^31-1

【時間複雜度&&優化】
O(1)

題目鏈接→HDU 5980 Find Small A

 Source Code

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<list>
#include<bitset>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-9
#define LL long long
#define PI acos(-1.0)
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 5005;
const int M = 100005;
const int inf = 1000000007;
const int mod = 1000000007;
const int MAXN = 100005;
int main()
{
    int n,i,ans;
    __int64 a;
    while(~scanf("%d",&n))
    {
        ans=0;
        for(i=0;i<n;i++)
        {
            scanf("%I64d",&a);
            while(a)
            {
                if(a%256==97)
                    ans++;
                a/=256;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}
菜鳥成長記
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章