"巴卡斯杯" 中国大学生程序设计竞赛 - 女生专场(重现)解题思路

Posted queuelovestack

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了"巴卡斯杯" 中国大学生程序设计竞赛 - 女生专场(重现)解题思路相关的知识,希望对你有一定的参考价值。

此文章可以使用目录功能哟↑(点击上方[+])

经过这么一次女生赛,告诉我们千万不要小瞧女生,不然会死得很惨,orz...

链接→"巴卡斯杯" 中国大学生程序设计竞赛 - 女生专场(重现)

 Problem 1001 Solving Order

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

 Problem Description

Welcome to HDU to take part in the first CCPC girls' competition!



As a pretty special competition, many volunteers are preparing for it with high enthusiasm.
One thing they need to do is blowing the balloons.

Before sitting down and starting the competition, you have just passed by the room where the boys are blowing the balloons. And you have found that the number of balloons of different colors are strictly different.

After thinking about the volunteer boys' sincere facial expressions, you noticed that, the problem with more balloon numbers are sure to be easier to solve.

Now, you have recalled how many balloons are there of each color.
Please output the solving order you need to choose in order to finish the problems from easy to hard.
You should print the colors to represent the problems.

 Input

The first line is an integer T which indicates the case number.
And as for each case, the first line is an integer n, which is the number of problems.
Then there are n lines followed, with a string and an integer in each line, in the i-th line, the string means the color of ballon for the i-th problem, and the integer means the ballon numbers.

It is guaranteed that:
T is about 100.
1≤n≤10.
1≤ string length ≤10.
1≤ bolloon numbers ≤83.(there are 83 teams :p)
For any two problems, their corresponding colors are different.
For any two kinds of balloons, their numbers are different.

 Output

For each case, you need to output a single line.

There should be n strings in the line representing the solving order you choose.

Please make sure that there is only a blank between every two strings, and there is no extra blank.

 Sample Input

3
3
red 1
green 2
yellow 3
1
blue 83
2
red 2
white 1

 Sample Output

yellow green red
blue
red white

 Problem Idea

解题思路:

【题意】
打气球的志愿者们比较蠢!
于是,打的气球越多,意味着题目越水>_<。
现在给你气球数,问你按照什么顺序做题,能够得以从易到难的顺序解决所有问题。

【类型】
C语言签到题

【分析】
这题,显然,我们要做的任务只是排序。
如果你刚接触程序设计,甚至不会c++的STL,可以先把气球数排序。然后按照i从小到大枚举,再依次枚举气球j,
if(气球数第i大的 == 当前这个j号气球的数量)then print(这个j号气球的颜色),复杂度O(n^2)。
但是,当然,如果你会STL,最简单的方法,就是按照本程序的方式排个序。这道题目就做完啦啊。

【时间复杂度&&优化】
O(nlogn)

题目链接→HDU 5702 Solving Order

 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<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define exp 1e-10
using namespace std;
const int N = 100005;
const int M = 15;
const int inf = 100000000;
const int mod = 2009;
struct balloon

    char color[M];
    int number;
s[M];
bool cmp(balloon x,balloon y)

    return x.number>y.number;

int main()

    int t,n,i;
    scanf("%d",&t);
    while(t--)
    
        scanf("%d",&n);
        for(i=0;i<n;i++)
            scanf("%s%d",s[i].color,&s[i].number);
        sort(s,s+n,cmp);
        for(i=0;i<n;i++)
            printf("%s%c",s[i].color,i!=n-1?' ':'\\n');
    
    return 0;

 Problem 1002 Desert

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

 Problem Description

A tourist gets lost in the desert with n liters of water. He drinks positive integer units of water each day.
Write a program to calculate how many different ways the tourist can drink up the water.

 Input

The first line contains the number of test cases T(T≤10).
Next T lines contain the number n(1≤n≤1000000) for each test case.

 Output

Output consists of T lines.

Each line contains the binary number which represents number of different ways to finish up the water specified in the test case.

 Sample Input

1
3

 Sample Output

100

Hint

3 liters of water can be comsumed in four different ways show in the following.
1. 1 1 1
2. 1 2
3. 2 1
4. 3

If we write 4 in binary, it's 100.

 Problem Idea

解题思路:

【题意】
一开始有数量为n(1<=n<=1e6)升的水,
我们每天可以喝数量为任意整数的水,问你有多少种方式可以把水喝完。

【类型】
简单排列组合 隔板法 整数拆分

【分析】
这道题其实就是——
问你,对于整数n,可以把n拆分成多少个不同的正整数序列

对于比赛型选手,显然此题不需要追求什么为什么

写几个找规律才是王道

但是,比赛过后,我们就要深究一下所以然
我们考虑排列组合中的隔板法。
就是n个数,中间有n-1个空位,
其中每一个空位中,都可以选择插入隔板,从而把这n个数分成若干份,恰好对应本题。

显然——
如果拆成1份,方案数是C(n-1,1-1)=C(n-1,0)
如果拆成2份,方案数是C(n-1,2-1)=C(n-1,1)
如果拆成3份,方案数是C(n-1,3-1)=C(n-1,2)
...
如果拆成n份,方案数是C(n-1,n-1)=C(n-1,n-1)
对应着二项式展开,它们的和恰好是2^(n-1)。
于是对应着,我们直接输出——
1个1
+(n-1)个0即可。

【时间复杂度&&优化】
O(n)

题目链接→HDU 5703 Desert

 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<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define exp 1e-10
using namespace std;
const int N = 100005;
const int M = 15;
const int inf = 100000000;
const int mod = 2009;
int main()

    int t,n,i;
    scanf("%d",&t);
    while(t--)
    
        scanf("%d",&n);
        printf("1");
        n--;
        for(i=0;i<n;i++)
            printf("0");
        puts("");
    
    return 0;

 Problem 1003 Luck Competition

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

 Problem Description

Participants of the Luck Competition choose a non-negative integer no more than 100 in their mind. After choosing their number, let K be the average of all numbers, and M be the result of K×. Then the lucky person is the one who choose the highest number no more than M. If there are several such people, the lucky person is chosen randomly.

If you are given a chance to know how many people are participating the competition and what their numbers are, calculate the highest number with the highest probability to win assuming that you're joining the competition.

 Input

There are several test cases and the first line contains the number of test cases T(T≤10).
Each test case begins with an integer N(1<N≤100), denoting the number of participants. And next line contains N−1 numbers representing the numbers chosen by other participants.

 Output

For each test case, output an integer which you have chosen and the probability of winning (round to two digits after the decimal point), seperated by space.

 Sample Input

3
4
1 2 3
4
1 1 2
4
20 30 40

 Sample Output

1 0.50
0 1.00
18 1.00

 Problem Idea

解题思路:

【题意】
n(2~100)个人参加一个游戏,
每个人选择1~100范围的数。
然后得到所有数的平均数,再*=2/3,设得到的数为m。
如果一个人选的数,比m小,且相距m最为接近,那么其便在所有选数相同的人中等概率中奖。

现在,我们也参加比赛,其他n-1个人所选择的数也已经确定了,并且我们知道。
问你,选什么数拥有最高中奖率,并输出。

【类型】
公式推导+标记

【分析】
假设我们选的数为x,其他n-1个人选的数之和为sum,那么M的值为

显然,x需要满足


要使x尽可能大,不等式右侧向下取整即可

得到x之后,获奖概率取决于同样选了x的人有几个,因为x的值比较小,我们完全可以在输入的时候保存每种数出现的次数


【时间复杂度&&优化】
O(nT)

题目链接→HDU 5704 Luck Competition

 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<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define exp 1e-10
using namespace std;
const int N = 105;
const int M = 15;
const int inf = 100000000;
const int mod = 2009;
int c[N];
int main()
//2(sum+x)/(3n)>=x
    int t,n,i,sum,x;
    scanf("%d",&t);
    while(t--)
    
        sum=0;
        memset(c,0,sizeof(c));
        scanf("%d",&n);
        for(i=1;i<n;i++)
        
            scanf("%d",&x);
            c[x]++;
            sum+=x;
        
        x=2*sum/(3*n-2);
        printf("%d %.2f\\n",x,1.0/(c[x]+1));
    
    return 0;

 Problem 1004 Clock

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

 Problem Description

Given a time HH:MM:SS and one parameter a, you need to calculate next time satisfying following conditions:

1. The angle formed by the hour hand and the minute hand is a.
2. The time may not be a integer(e.g. 12:34:56.78), rounded down(the previous example 12:34:56).

 Input

The input contains multiple test cases.

Each test case contains two lines.
The first line is the time HH:MM:SS(0≤HH<12,0≤MM<60,0≤SS<60).
The second line contains one integer a(0≤a≤180).

 Output

For each test case, output a single line contains test case number and the answer HH:MM:SS.

 Sample Input

0:59:59
30
01:00:00
30

 Sample Output

Case #1: 01:00:00
Case #2: 01:10:54

 Problem Idea

解题思路:

【trick&&吐槽】
最终的HH值可能会超过12

所以要对12取余,因为这个,错了n发,其他问题还好

【题意】
时间为12小时制。
告诉你一个时刻,让你输出在这个时刻之后的下一个时刻,
满足:该时刻,时针分针掐好相差某个的角度为a。
(注意,满足要求的时刻不一定是恰好以秒为单位,可以是秒与秒之间的时刻,我们可以向下取整)

【类型】
追及问题,判断

【分析】
如何使得时针与分针的角度恰好相差某个角度呢?
钟表有360个度,

一,考虑时针位置
每小时为30度
每分钟为1/2度
每秒钟为1/120度
于是我们不妨使得所有与角度相关的单位都*=120,转化成整数,告别精度误差。
(其实也就可以看做是为:以秒为基本单位。)
转变为:
每小时为3600°
每分钟为60°
每秒钟为1°

二,考虑分针位置
每分钟为6度
每秒钟为0.1度
我们一样*=120,转变为——
每分钟为720°
每秒钟为12°

首先先将当前时针和分针的位置确定

为了确保满足时针和分针夹角为a的情况不是当前时间,我们先将时间往后拨1秒,即分针走12°,时针走1°

然后判断时针分针的位置关系即可,主要分为下列四种位置关系

1.分针追上时针的夹角为θ>=180°,夹角a<360°-θ


那么时针和分针达到a的时间为(θ-a*120)/11°

2.分针追上时针的夹角为θ>=180°,夹角a≥360°-θ


那么时针和分针达到a的时间为(θ-(360°-a)*120)/11°

3.分针追上时针的夹角为θ<180°,夹角a<=θ


那么时针和分针达到a的时间为(d-a*120)/11°

4.分针追上时针的夹角为θ<180°,夹角a>θ


那么时针和分针达到a的时间为(d+a*120)/11°

【时间复杂度&&优化】
O(T)

题目链接→HDU 5705 Clock

 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<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define exp 1e-10
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 100005;
const int M = 120;
const int inf = 1600000000;
const int mod = 2009;
int solve(int u,int v,int a)

    int d,ans;
    d=(v+M*360-u)%(M*360);
    if(d>=M*180)
    
        if(a*M<360*M-d)
            ans=v+(d-a*M)/11;
        else
            ans=v+(d-(360-a)*M)/11;
    
    else
    
        if(a*M<=d)
            ans=v+(d-a*M)/11;
        else
            ans=v+(d+a*M)/11;
    
    return ans;

int main()

    //u=1/10*(m*60+s);
    //v=1/120*(h*3600+m*60+s);
    int h,m,s,a,u,v,p=1,ss,mm,hh,ans;
    while(~scanf("%d:%d:%d%d",&h,&m,&s,&a))
    
        u=(12*(m*60+s+1))%(M*360);
        v=h*3600+m*60+s+1;
        ans=solve(u,v,a);
        hh=ans/3600%12;
        mm=ans/60%60;
        ss=ans%60;
        printf("Case #%d: %02d:%02d:%02d\\n",p++,hh,mm,ss);
    
    return 0;


 Problem 1005 GirlCat

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

 Problem Description

As a cute girl, Kotori likes playing ``Hide and Seek'' with cats particularly.
Under the influence of Kotori, many girls and cats are playing ``Hide and Seek'' together.
Koroti shots a photo. The size of this photo is n×m, each pixel of the photo is a character of the lowercase(from `a' to `z').
Kotori wants to know how many girls and how many cats are there in the photo.

We define a girl as -- we choose a point as the start, passing by 4 different connected points continuously, and the four characters are exactly ``girl'' in the order.
We define two girls are different if there is at least a point of the two girls are different.
We define a cat as -- we choose a point as the start, passing by 3 different connected points continuously, and the three characters are exactly ``cat'' in the order.
We define two cats are different if there is at least a point of the two cats are different.

Two points are regarded to be connected if and only if they share a common edge.

 Input

The first line is an integer T which represents the case number.

As for each case, the first line are two integers n and m, which are the height and the width of the photo.
Then there are n lines followed, and there are m characters of each line, which are the the details of the photo.

It is guaranteed that:
T is about 50.
1≤n≤1000.
1≤m≤1000.
∑(n×m)≤2×1000000.

 Output

As for each case, you need to output a single line.
There should be 2 integers in the line with a blank between them representing the number of girls and cats respectively.

Please make sure that there is no extra blank.

 Sample Input

3
1 4
girl
2 3
oto
cat
3 4
girl
hrlt
hlca

 Sample Output

1 0
0 2
4 1

 Problem Idea

解题思路:

【题意】
我们拍了一张照片!
照片是n*m个像素的!
对于每个像素,都是一个小写英文字符。
如果连着走4步,是"girl"就是一个girl
如果连着走3步,是"cat"就是一只cat
然后问你,这个图上有多少个girl多少只cat

【类型】
简单bfs or dfs

【分析】
显然,如果你很熟练的话,只要暴力枚举起点,然后做记录匹配阶段的暴力dfs或者bfs即可。
然而,这题的友好之处,在于——
它给并不会算法的人,提供了一个用汗水交换丰收=w=的机会。
你只要写一串for,或者一大通if!就可以顺利获得一个AC啦!
for(i)for(j)
if(a[i][j]=='g')

if(a[i-1][j]=='l')

if(...)

if(a[i+1][j]=='l')

if(...)

if(a[i][j-1]=='l')

if(...)

if(a[i][j+1]=='l')

if(...)


就这样 = =
23333

【时间复杂度&&优化】
O(Tnm)

题目链接→HDU 5706 GirlCat

 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<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define exp 1e-10
using namespace std;
const int N = 1005;
const int M = 15;
const int inf = 100000000;
const int mod = 2009;
char s[N][N],ch[2][5]="girl","cat";
bool v[N][N];
int ans[2],n,m;
bool check(int x,int y)

    return x>=0&&x<n&&y>=0&&y<m;

void dfs(int x,int y,int k,int t)

    if(!check(x,y)||s[x][y]!=ch[t][k])
        return;
    v[x][y]=true;
    if(t&&k==2||!t&&k==3)
    
        ans[t]++;
        return;
    
    dfs(x+1,y,k+1,t);
    dfs(x,y+1,k+1,t);
    dfs(x-1,y,k+1,t);
    dfs(x,y-1,k+1,t);

int main()

    int t,i,j;
    scanf("%d",&t);
    while(t--)
    
        ans[0]=ans[1]=0;
        memset(v,false,sizeof(v));
        scanf("%d%d",&n,&m);
        for(i=0;i<n;i++)
            scanf("%s",s[i]);
        for(i=0;i<n;i++)
            for(j=0;j<m;j++)
                if(!v[i][j])
                
                    if(s[i][j]=='g')
                        dfs(i,j,0,0);
                    else if(s[i][j]=='c')
                        dfs(i,j,0,1);
                
        printf("%d %d\\n",ans[0],ans[1]);
    
    return 0;


 Problem 1006 Combine String

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

 Problem Description

Given three strings a, b and c, your mission is to check whether c is the combine string of a and b.
A string c is said to be the combine string of a and b if and only if c can be broken into two subsequences, when you read them as a string, one equals to a, and the other equals to b.
For example, ``adebcf'' is a combine string of ``abc'' and ``def''.

 Input

Input file contains several test cases (no more than 20). Process to the end of file.
Each test case contains three strings a, b and c (the length of each string is between 1 and 2000).

 Output

For each test case, print ``Yes'', if c is a combine string of a and b, otherwise print ``No''.

 Sample Input

abc
def
adebcf
abc
def
abecdf

 Sample Output

Yes
No

 Problem Idea

解题思路:

【trick&&吐槽】
这道题不能直接用指针的方法做贪心,即下面的程序是错误的
void greedy_wa()

int pa = 1;
int pb = 1;
int pc = 1;
while (pc <= g)

if (pa <= n && a[pa] == c[pc])++pa;
else if (pb <= m && b[pb] == c[pc])++pb;
else break;
++pc;

puts(pc > g ? "Yes" : "No");

因为可能有这样的数据:
abce
abcd
abcdabce
我们本来为了匹配,应当释放正确的前缀,即第二个。
然而我们如果贪心做的话,有可能把首先选择了第一个前缀的abc,这样子就错掉了。

【题意】
给你两个字符串a,b
然后再给你一个字符串c(长度都在2000范围内)
问你——能否恰把c分成两个字符串a,b。

【类型】
DP

【分析】
本题的DP类似于LCS(longest common subsequence)(如果不了解的可以搜一下)。
只是,
f[i][j]表示第一个字符串用了前i个位置(第i个位置已匹配),第二个字符串的前j个位置(第j个位置已匹配)
是否可以对c串成功匹配(成功匹配则必然会匹配到c串的前i+j个位置)。
f[i][j]==1则表示可以成功匹配
f[i][j]==0则表示无法成功匹配

显然,初始只有f[0][0]==1
所以,我们有——
f[i][j]= f[i-1][j]&&(a[i]==c[i+j])
|| f[i][j-1]&&(b[j]==c[i+j])
这样,最终f[n][m]==1则为Yes否则为No

【时间复杂度&&优化】
O(nm)

题目链接→HDU 5707 Combine String

 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<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define exp 1e-10
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 2005;
const int M = 120;
const int inf = 1600000000;
const int mod = 2009;
char a[N],b[N],c[N];
int dp[N][N];
int main()

    int i,j,n,m,k;
    while(~scanf("%s",a+1))
    
        memset(dp,0,sizeof(dp));
        scanf("%s",b+1);
        scanf("%s",c+1);
        n=strlen(a+1);
        m=strlen(b+1);
        k=strlen(c+1);
        if(n+m!=k)
        
            puts("No");
            continue;
        
        dp[0][0]=1;
        for(i=0;i<=n;i++)
            for(j=0;j<=m;j++)
            
                if(i>0&&c[i+j]==a[i])
                    dp[i][j]|=dp[i-1][j];
                if(j>0&&c[i+j]==b[j])
                    dp[i][j]|=dp[i][j-1];
            
        /*for(i=0;i<=n;i++)
        
            for(j=0;j<=m;j++)
                printf("%d ",dp[i][j]);
            puts("");
        */
        if(dp[n][m])
            puts("Yes");
        else
            puts("No");
    
    return 0;


 Problem 1007 Alice and Bob

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

 Problem Description

Alice and Bob are playing a stone game in a board of n×m cells.

In the begining, the stone is in the upperleft cell. And in each turn, they can move the stone one cell to the right or one cell down, or diagonally k cells down to the right, which means if you are at (x,y), then you could move into (x+1,y), (x,y+1) or (x+k,y+k) at the next step. The player who can not move loses. They play in turns and Alice moves first.

Now given n, m and k, could you tell me who is the winner?

 Input

First line contains an integer T(1≤T≤10), denoting the number of test cases.

In each test case, the first line is two integers Q and k.
In the following Q lines, each line contains n and m.(1≤Q≤1000,1≤k,n,m≤1000,000,000)

 Output

For each test case, output Q lines.
If Alice is the winner, output ``Alice''. Otherwise ``Bob''.

 Sample Input

2
2 1
4 5
3 4
2 3
4 5
5 6

 Sample Output

Alice
Alice
Alice
Bob

 Problem Idea

解题思路:

【trick&&吐槽】
判定奇偶性的时候——
%2==1往往是错的,有时%2==-1。还是&1 来判定奇偶性的方法比较靠谱

【题意】
给你一个棋盘,大小为n*m。
我们一开始在(1,1)点,
如果我们当前在(x,y),
那么我们可以在一步之内走到
(x+1,y)
(x,y+1)
(x+k,y+k)
先告诉你k,k∈[1,1e9]
然后有q组询问,q∈[1,1000]
对于每个q,告诉你(n,m)
n∈[1,1e9],m∈[1,1e9]。
无法可走便输了,问先手必胜还是后手必胜。

【类型】
博弈 打表找规律

【分析】
对于这题,n和m都是1e9,太大了。
于是我们要考虑O(1)出解。
即打表找规律。
至于,什么是打表找规律呢?
1,问题数据规模很小,我们可以本地预处理出所有解,然后存到代表段数组中,O(1)输出
2,问题数据规模很大,我们可以本地跑出小数据的答案,然后猜解大数据的规律。

对于这题——
K==1时,表示这样的:
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

K==2时,表示这样的:
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 0 1 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
0 1 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
1 0 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
0 1 1 0 1 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 0 1 1 0 1 1 0 1 0 1 0 1 0 1 0 1 0 1 0
0 1 1 0 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1
1 0 1 1 0 1 1 0 1 1 0 1 0 1 0 1 0 1 0 1
0 1 1 0 1 1 0 1 1 0 1 0 1 0 1 0 1 0 1 0
1 0 1 1 0 1 1 0 1 1 0 1 1 1 1 1 1 1 1 1
0 1 1 0 1 1 0 1 1 0 1 1 0 1 0 1 0 1 0 1
1 0 1 1 0 1 1 0 1 1 0 1 1 0 1 0 1 0 1 0
0 1 1 0 1 1 0 1 1 0 1 1 0 1 1 1 1 1 1 1
1 0 1 1 0 1 1 0 1 1 0 1 1 0 1 1 0 1 0 1
0 1 1 0 1 1 0 1 1 0 1 1 0 1 1 0 1 0 1 0
1 0 1 1 0 1 1 0 1 1 0 1 1 0 1 1 0 1 1 1
0 1 1 0 1 1 0 1 1 0 1 1 0 1 1 0 1 1 0 1
1 0 1 1 0 1 1 0 1 1 0 1 1 0 1 1 0 1 1 0

K==3时,表示这样的:
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
0 1 0 1 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
1 0 1 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
0 1 0 1 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
1 0 1 1 0 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1
0 1 0 1 1 0 1 1 0 1 0 1 0 1 0 1 0 1 0 1
1 0 1 1 0 1 0 1 1 0 1 0 1 0 1 0 1 0 1 0
0 1 0 1 1 0 1 1 0 1 0 1 0 1 0 1 0 1 0 1
1 0 1 1 0 1 0 1 1 0 1 1 1 1 1 1 1 1 1 1
0 1 0 1 1 0 1 1 0 1 0 1 1 0 1 0 1 0 1 0
1 0 1 1 0 1 0 1 1 0 1 1 0 1 0 1 0 1 0 1
0 1 0 1 1 0 1 1 0 1 0 1 1 0 1 0 1 0 1 0
1 0 1 1 0 1 0 1 1 0 1 1 0 1 0 1 1 1 1 1
0 1 0 1 1 0 1 1 0 1 0 1 1 0 1 1 0 1 0 1
1 0 1 1 0 1 0 1 1 0 1 1 0 1 0 1 1 0 1 0
0 1 0 1 1 0 1 1 0 1 0 1 1 0 1 1 0 1 0 1
1 0 1 1 0 1 0 1 1 0 1 1 0 1 0 1 1 0 1 1

我们发现到,
对于K>1时,
对于f[K][K]~f[K][∞],答案都是1(先手必胜)
对于f[K][K]~f[∞][K],答案都是1(先手必胜)

对于f[2K][2K]~f[2K][∞],答案都是1(先手必胜)
对于f[2K][2K]~f[∞][2K],答案都是1(先手必胜)

对于f[3K][3K]~f[3K][∞],答案都是1(先手必胜)
对于f[3K][3K]~f[∞][3K],答案都是1(先手必胜)

......

即f[nK][nK]~f[nK][∞],答案都是1(先手必胜)
f[nK][∞]~f[nK][nK],答案都是1(先手必胜)

对于其它的f(i,j),我们要找到第一个位置(pK,pK),满足i>=pK且j>=pK。

然后:
如果p是奇数,那么与(pK,pK)同奇偶性的(即横纵坐标之和同奇偶性)都是必胜点,否则为必败点
如果p是偶数,那么与(pK,pK)同奇偶性的(即横纵坐标之和同奇偶性)都是必败点,否则为必胜点

然而,对于K==1的时候,是特例的。不论p是奇数还是偶数,与(pK,pK)同奇偶性的(即横纵坐标之和同奇偶性)都是必败点,否则为必胜点


这里再尝试一下证明:(我们不妨把题目中的由从(1,1)->(n,m)),改变方向为从(n,m)走到(1,1),这样答案不变,然而考虑和看起来更直观。
对于初始K==1的,对于(n,m)==(X,X),初始点(先手)的胜负态为:
(1,1):必败态
(1,x)为(1,x-1)的反态,(x,1)为(x-1,1)的反态,为必胜态和必败态的依次轮转。
(2,2):必胜态
(2,x)和(x,2):都可以找到(1,x)和(1,x-1)的两个前驱,必然有必败态的前驱,所以全为必胜态
接下来所有点都找不到任何一个必败态的前驱,其状态又归回于——
(3,3):必败态
(3,x)为(3,x-1)的反态,(x,3)为(x-1,3)的反态,为必胜态和必败态的依次轮转。
(4,4):必胜态
(4,x)都可以找到(3,x)和(3,x-1)的两个前驱,(4,x)都可以找到(3,x)和(3,x-1)的两个前驱,必然有必败态的前驱,所以全为必胜态
……
所以我们对K==1条件下的结论是正确的

对于初始K>1的,我们不妨使得K+=1,然后,对于(n,m)==(X,X),初始点(先手)的胜负态为:
(1~K-1,x)与(x,1~K-1),这些点都是不涉及到斜着走K步的情况的,于是胜负只与奇偶性有关,即偶点必败奇点必胜。
(K,K):必胜态,因为其可以一步到(1,1)这个必败态。
(K,K~x)和(K~x,K),其既可以达到奇点,又可以达到偶点,所以是必胜态。

就是按照这个过程,奇偶归类,虽然很繁琐,然而我们可以得到结论的证明>_<

题目链接→HDU 5708 Alice and Bob

 Source Code

#include<stdio.h> 
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre()  freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); 
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b)  if (b>a)a = b; 
template <class T1, class T2>inline void gmin(T1 &a, T2 b)  if (b<a)a = b; 
const int N = 0, M = 0, Z = 1e9 + 7, ms63 = 0x3f3f3f3f;
int casenum, casei;
int Q, K, n, m;
int f[100][100];
int dp(int n, int m)

	if (n == 1 && m == 1)return 0;
	if (~f[n][m])return f[n][m];
	if (n > 1 && !dp(n - 1, m))return f[n][m] = 1;
	if (m > 1 && !dp(n, m - 1))return f[n][m] = 1;
	if (n > K&&m > K&&!dp(n - K, m - K))return f[n][m] = 1;
	return f[n][m] = 0;

void table(int k)

	K = k;
	for (n = 1; n <= 20; ++n)
	
		for (m = 1; m <= 20; ++m)
		
			MS(f, -1);
			printf("%d ", dp(n, m));
		puts("");
	

int main()

	//table(1);table(2);table(3);
	scanf("%d", &casenum);
	for (casei = 1; casei <= casenum; ++casei)
	
		scanf("%d%d", &Q, &K); ++K; //首先先使得K+=1
		while (Q--)
			
			scanf("%d%d", &n, &m);

			//规律1:如果较小宽度为K的倍数,那么先手必胜
			if (n > m)swap(n, m); //n<=m
			if (n%K == 0)
			
				puts("Alice");
				continue;
			

			//规律2:距离顶角元素距离的奇偶性,一样对答案有所影响(特判K==2)
			int len = n / K;
			if (K > 2 && (len & 1))
			
				puts((n + m) % 2 == 0 ? "Alice" : "Bob");
			
			else
			
				puts((n + m) % 2 == 0 ? "Bob" : "Alice");
			
		
	
	return 0;


 Problem 1008 Claris Loves Painting

Accept: 0    Submit: 0
Time Limit: 10000/5000 MS (Java/Others)     Memory Limit : 256000/256000 K (Java/Others)

 Problem Description

Claris loves painting very much, so he painted a tree with beautiful colors.

The tree is a rooted tree with n nodes which are conveniently labeled by 1,2,...,n. Its root is the 1-st node, and the i-th node is painted with color ci. If ci=cj, then we think these two nodes have the same color.

We define depthi as the distance between the i-th node and the root, and simply, the distance between two adjacent nodes is always 1.

Standing in front of this beautiful tree, Claris comes up with m questions.
In each question, there are two integers x and d, which means that Claris wants to know the number of different kinds of colors occur in S, where S=v|v in x′s subtree and depthv≤depthx+d.

 Input

The first line of the input contains an integer T(1≤T≤500), denoting the number of test cases.

In every test case, there are two integers n(1≤n≤100000) and m(1≤m≤100000) in the first line, denoting the number of nodes and queries.
The second line contains n integers, the i-th integer ci(1≤ci≤n) denotes the color of the i-th node.
The third line contains n−1 integers, the i-th integer fi+1(1≤fi<i) denotes the father of the i+1-th node.
In the following m lines, each line contains two integers x(1≤x≤n) and d(0≤d<n), denoting each query.

The input has been encoded, if you read x and d, the real x and d are x⊕last and d⊕last, where last is the answer of the previous query and ⊕ means bitwise exclusive-or.

Notice :
If it is the first query in this test case, then last=0.
It is guaranteed that ∑n≤500000 and ∑m≤500000.

 Output

For each query output a single integer in a line, denoting the answer.

 Sample Input

1
5 8
1 3 3 2 2
1 1 3 3
1 0
0 0
3 0
1 3
2 1
2 0
6 2
4 1

 Sample Output

1
2
3
1
1
2
1
1

 Problem Idea

解题思路:

【题意】
给你一棵n(1e5)个节点的树
每个节点都有一个颜色
有m(1e5)个询问
对于每个询问,
问你以一个节点为子树的根,距离其深度<=d的所有节点中,有多少种不同颜色。
强制在线。

【类型】
动态节点线段树

【分析】
首先,这道题的解题思想是这样的——
我们做dfs,然后自底向上,维护两个东西。
1,每个颜色对应的最大深度
2,每个深度对应的颜色数

然后,我们对于一个新节点(显然处理这个节点的时候,这个节点是位于父节点的结构位置的)
我们首先,给它建立一棵线段树。在这棵线段树是基于全0线段树展开的。
唯一不同的是,在dep[x]的位置,权值要为1。
于是我们按照这个原理,在不超过logn的复杂度内建立一棵

以上是关于"巴卡斯杯" 中国大学生程序设计竞赛 - 女生专场(重现)解题思路的主要内容,如果未能解决你的问题,请参考以下文章

"巴卡斯杯" 中国大学生程序设计竞赛 - 女生专场

"字节跳动杯"2018中国大学生程序设计竞赛-女生专场 Solution

2019中国大学生程序设计竞赛(CCPC) - 网络选拔赛

起点旅行杯"睡不着的睡美人"之"最美中国留学生"评选投票开始lua!

C语言 学生成绩管理系统

C语言 学生成绩管理系统