Jump and Jump...

Time Limit: 2000/1000 MS
(Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 0    Accepted Submission(s): 0

Problem Description

There are n kids and they want to know who can jump
the farthest. For each kid, he can jump three times and the distance he jumps
is maximum distance amount all the three jump. For example, if the distance of
each jump is (10, 30, 20), then the farthest distance he can jump is 30. Given
the distance for each jump of the kids, you should find the rank of each kid.

Input

There are multiple test cases. The first
line of input contains an integer T (1≤T≤100), indicating the number of test cases.
For each test case: The first line contains an integer n (2≤n≤3), indicating the number of kids. For the
next n lines, each line contains three integers ai,bi and ci (1≤ai,bi,ci,≤300), indicating the distance for each jump
of the i-th kid. It's guaranteed that the final rank of each kid
won't be the same (ie. the farthest distance each kid can jump won't be the
same).

Output

For each test case, you should output a
single line contain n integers, separated by one space. The i-th integer indicating the rank of i-th kid.

Sample Input

2

3

10 10 10

10 20 30

10 10 20

2

3 4 1

1 2 1

Sample Output

3 1 2

1 2

Hint

For the first case, the farthest
distance each kid can jump is 10, 30 and 20. So the rank is 3, 1, 2.

Jump and Jump...

Time Limit: 2000/1000 MS
(Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 714    Accepted Submission(s): 422

问题描述

n小孩在比赛跳远,看谁跳的最远。每个小孩可以跳3次,这个小孩的成绩就是三次距离里面的最大值。例如,一个小孩跳3次的距离分别时10, 30和20,那么这个小孩的成绩就是30。给出每个孩子三次跳的距离,问最终每个孩子的排名是多少。

输入描述

输入文件的第一行有一个整数T (1≤T≤100),表示测试数据的组数。对于每组测试数据:第一行包括一个整数n (2≤n≤3), 表示孩子的数目. 接下来n行, 每行包含三个整数ai,bici (1≤ai,bi,ci,≤300), 表示第i个小孩每次的跳的距离。输入数据保证每个孩子的成绩互不相同。

输出描述

对于每组数据,输出一行包含n个整数,用一个空格隔开。第i个数表示第i个小孩的最终名次。

输入样例

2

3

10 10 10

10 20 30

10 10 20

2

3 4 1

1 2 1

输出样例

3 1 2

1 2

提示:

对于第一组数据,3个孩子的成绩分别时10, 20和30。因此他们最终排名依次是3, 1和2.

想复杂了,第一次做这种比赛;其实就是把最好的成绩排个顺序,就可以了!

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std; struct node
{
int id;
int mlen;
}a[];
int cmp(node x,node y)
{
return x.mlen>y.mlen;
}
int ss[];
int main()
{
int T;
int ans,i,j,n;
int x,y,z;
scanf("%d",&T);
while(T--)
{
memset(a,,sizeof(a));
scanf("%d",&n);
for(i=;i<=n;i++)
{
scanf("%d%d%d",&x,&y,&z);
int tmp=max(x,y);
tmp=max(tmp,z);
a[i].id=i;
a[i].mlen=tmp;
}
sort(a+,a+n+,cmp);
for(i=;i<=n;i++)
ss[a[i].id]=i;
printf("%d",ss[]);
for(j=;j<=n;j++)
printf(" %d",ss[j]);
printf("\n"); }
return ;
}

Taking Bus

Time Limit: 10000/5000 MS
(Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 0    Accepted Submission(s): 0

Problem Description

Bestland has a very long road and there
are n bus station along the road, which are numbered 1 to n from left to right. There are m persons wanting to take the bus to some
other station. You task is to find the time needed for each person. Note: All
the other information you need is below. Please read the statment carefully.

Input

There are multiple test cases. The first
line of input contains an integer T (1≤T≤60), indicating the number of test cases.
For each test case: The first line contains two integers n and m (2≤n,m≤105), indicating the number of bus stations
and number of people. In the next line, there are n−1 integers, d1,d2,…,dn−1 (1≤di≤109). The i-th integer means the distance between
bus station i and i+1 is di (1≤i<n). In the next m lines, each contains two integers xi and yi (1≤xi,yin,xiyi), which means i-th person is in bus station xi and wants goto bus station yi. (1≤im)

What else you should know is that for the i-th person, the bus starts at bus
station ((i−1) mod n)+1 and drives to right. When the bus
arrives at station n, it will turn around and drive from
right to left. Similarly, When the bus arrives at station 1, it will turn around and drive from
left to right. You can assume that the bus drives one meter per second. And you
should only consider the time that the bus drives and ignore the others.

Output

For each person, you should output one
integer which is the minimum time needed before arriving bus station yi.

Sample Input

1

7 3

2 3 4 3 4 5

1 7

4 5

5 4

Sample Output

21

10

28

Hint

For the first person, the bus starts at
bus station 1, and the person takes in bus at time 0. After 21 seconds, the bus
arrives at bus station 7. So the time needed is 21 seconds. For the second
person, the bus starts at bus station 2. After 7 seconds, the bus arrives at
bus station 4 and the person takes in the bus. After 3 seconds, the bus arrives
at bus station 5. So the time needed is 10 seconds. For the third person, the
bus starts at bus station 3. After 7 seconds, the bus arrives at bus station 5
and the person takes in the bus. After 9 seconds, the bus arrives at bus
station 7 and the bus turns around. After 12 seconds, the bus arrives at bus
station 4. So the time needed is 28 seconds.

Taking Bus

Time Limit: 10000/5000 MS
(Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 954    Accepted Submission(s): 255

问题描述

Bestland有一条非常长的马路,马路上设有n个公交汽车站。公交汽车站从左到右标号为1到n。有m个人想要乘公交。你的任务是找出每个人到终点为止所需要的时间。注意:你需要用来解决这道题目的信息在Input里面,请仔细阅读。

输入描述

输入的第一行包含一个整数T (1≤T≤60),表示测试数据的组数。对于每组测试数据:第一行包含两个整数nm (2≤n,m≤105),表示公交车站的数目和乘客的数目。 接下来一行包含n−1个整数, d1,d2,…,dn−1 (1≤di≤109). 
di表示第i个公交站和第i+1个公交站之间的距离。在接下来的m行, 每行包含两个整数xiyi (1≤xi,yin,xiyi), 表示第i个人时刻0的时候在第xi个公交站并且想要到第yi个公交站去。(1≤im)

对于第i个人, 公交车在第((i−1) mod n)+1个公交站点在时刻0的时候,并且公交一开始往右开。公交到达站点n的时候会立刻转向往左开,同样当公交到达站点1的时候也会立刻转向往右开。你可以认为公交每秒只开一个单位距离,你只需要考虑公交开的时间。

输出描述

对于每个人,输出到达yi个公交站点需要的最少时间。

输入样例

1

7 3

2 3 4 3 4 5

1 7

4 5

5 4

输出样例

21

10

28

提示:

对于第一个人, 公交在站点1出发, 然后这个人在时刻0上车。21秒之后,公交到达站点7。

对于第二个人,公交在站点2出发。7秒之后,公交到达站点4,这个人上车。之后又过了3秒,公交到达站点5.总共用了10秒。

对于第三个人,公交在站点3出发。7秒之后,公交到达站点5,这个人上车。之后过了9秒,公交达到站点7,然后转向开往站点0。之后经过12秒,公交达到站点4。因此总共需要28秒时间。

出这题的时间也不够快,其实就是个模拟搭公车,自己动手试试就知道了!

分情况讨论就这么简单。。。我也是醉了。

#include<cstdio>
#include<iostream>
using namespace std; __int64 lenz[],lenf[],len;//被I64害了!
int main()
{
int T,n,m;
int i,j,k;
int st,et;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
lenz[]=;
lenf[n]=;
for(i=;i<=n;i++)
{
scanf("%I64d",&len);
lenz[i]=lenz[i-]+len;
}
for(i=n-;i>;i--)
{
lenf[i]=lenz[n]-lenz[i];
}
int ss;
len=;
for(i=;i<=m;i++)
{
scanf("%d%d",&st,&et);
ss=(i-)%n+;
if(st==et) len=;
else if(st>et)
{
// if(ss>st)
len=lenz[n]-lenz[ss]+lenf[et];
// else
// len=lenz[n]-lenz[ss]+lenf[et];
}
else
{
if(ss==st)
len=lenz[et];
if(ss>st)
len=lenf[]+lenz[n]-lenz[ss]+lenz[et];
else
len=lenz[et]-lenz[ss];
}
printf("%I64d\n",len);
}
}
return ;
}

Matching on Array

Time Limit: 4000/2000 MS
(Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 0    Accepted Submission(s): 0

Problem Description

Alice has a sequence {a1,a2,…,an} with n positive integers. Bob has some
positive integer sequences with different size. Alice wants to know the total
occurrences of every sequence Bob has in Alice's sequence (the occurrences are
allowed to overlap).

We say one sequence B occurs in another sequence A if there is a contiguous subsequence of
A that is the same as B after scaled by a positive real factor.

For example A={2,4,8,16},B={1,2} then B occurs three times in A. The occurrences are {2,4}, {4,8} and {8,16}. And the factor is 0.5, 0.25 and 0.125.

Input

There are multiple test cases. The first
line of input contains an integer T (1≤T≤30), indicating the number of test cases.
For each test case:

The first line contains two integer n and m  (1≤n,m≤100000), indicating the size of Alice's
sequence and the number of sequences Bob has. In the next line, there are n integers, a1,a2,…,an, indicating Alice's sequence. In the
following m lines, each starts with an integer ki(1≤ki≤300000) - the size of the sequence. Then ki space separated positive integers
follow, indicating the sequence.

The total sum of ki is less than or equal to 1000000. Other
integers are between 1 and 10000, inclusive.

Output

For each test case, output a single line
with a single integer, indicating the total number of occurrences.

Sample Input

2

4 1

2 4 8 16

2 1 2

5 3

2 4 2 4 6

3 1 2 1

1 5

2 16 8

Sample Output

3

7

Hint

For sample 1, please refer to the
problem description. For sample 2, {1, 2, 1} occurs only once, {5} occurs five
times and {16, 8} occurs only once.

Matching on Array

Time Limit: 4000/2000 MS
(Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 142    Accepted Submission(s): 28

问题描述

Alice有一个大小为n的正整数序列{a1,a2,…,an}。Bob也有一些正整数序列。Alice想要知道对于Bob的每个序列,他们在Alice的序列中出现的总次数是多少。

对于两个序列AB,如果A中有一个连续子序列在乘以某个缩放系数之后和B一样的话,那么BA中出现。

例如,A={2,4,8,16},B={1,2}, 那么BA中出现了3次。对应A中的子序列为{2,4}, {4,8}和{8,16},缩放系数分别是 0.5, 0.25和0.125。

输入描述

输入第一行包含一个整数T (1≤T≤30)表示测试数据组数。对于每组数据:

第一行包含两个整数nm  (1≤n,m≤100000),分别表示Alice的序列大小和Bob拥有的序列的个数。接下来一行包含n个整数,a1,a2,…,an,表示Alice的序列。接下来m行,每行的第一个数是ki(1≤ki≤300000)表示这个序列的大小。接下来ki个用空格分开的正整数,表示这个序列。

保证所有ki的和小于等于1000000。其他整数范围介于1和10000之间(包括1和10000)。

输出描述

对于每组数据,输出一个整数表示出现的总次数。

输入样例

2

4 1

2 4 8 16

2 1 2

5 3

2 4 2 4 6

3 1 2 1

1 5

2 16 8

输出样例

3

7

还没想到很好的办法,题目意思就是匹配数组!问B数组的子数组在A的子数组中出现的次数(倍数关系)有好方法的可以和我讨论哦。

#include <iostream>
#include <fstream>
#include <algorithm>
using namespace std; const int maxn = + ; struct Tnode {
int a, b;
Tnode (int c = , int d = ) : a(c), b(d) {
}
} d[maxn]; bool operator < (Tnode &a, Tnode &b) {
if (a.a == b.a) return a.b < b.b;
return a.a < b.a;
} bool operator > (Tnode &a, Tnode &b) {
if (a.a == b.a) return a.b > b.b;
return a.a > b.a;
} bool operator == (Tnode &a, Tnode &b) {
return a.a == b.a && a.b == b.b;
} int gcd(int a, int b) {
if (b == ) return a;
return gcd(b, a % b);
} bool cmp(int a, int b) {
return d[a] < d[b];
} int n, m;
int ra[maxn], rb[maxn], sum[maxn], rank[maxn], sa[maxn], inx[maxn]; bool equal(int *r, int a, int b, int j) {
return r[a] == r[b] && r[a + j] == r[b + j];
} void Sa() {
int i, j, p, *x = ra, *y = rb, *t, m = n;
for (i = ; i < m; i++) sum[i] = ;
for (i = ; i < n; i++) sum[ x[i] = rank[i] ]++;
for (i = ; i < m; i++) sum[i] += sum[i - ];
for (i = n - ; i > -; i--) sa[ --sum[ x[i] ] ] = i; for (j = , p = ; p < n; j <<= ) {
for (i = n - j, p = ; i < n; i++) y[p++] = i;
for (i = ; i < n; i++)
if (sa[i] >= j) y[p++] = sa[i] - j; for (i = ; i < m; i++) sum[i] = ;
for (i = ; i < n; i++) sum[ x[i] ]++;
for (i = ; i < m; i++) sum[i] += sum[i - ];
for (i = n - ; i > -; i--) sa[ --sum[ x[ y[i] ] ] ] = y[i]; t = x; x = y; y = t;
p = ;
x[ sa[] ] = ;
for (i = ; i < n; i++)
if (equal(y, sa[i], sa[i - ], j)) x[ sa[i] ] = p - ;
else x[ sa[i] ] = p++;
}
n--;
for (i = ; i < n; i++) sa[i] = sa[i + ];
} void Init() {
scanf("%d%d", &n, &m);
int pre = , c;
scanf("%d", &pre);
for (int i = ; i < n - ; i++) {
scanf("%d", &c);
d[i] = Tnode(c / gcd(pre, c), pre / gcd(pre, c));
inx[i] = i;
pre = c;
}
d[n - ] = Tnode(, );
inx[n - ] = n - ; sort(inx, inx + n, cmp); int p = ;
rank[ inx[] ] = p;
for (int i = ; i < n; i++)
if (d[ inx[i] ] == d[ inx[i - ] ]) rank[ inx[i] ] = p;
else rank[ inx[i] ] = ++p;
Sa();
} Tnode p[maxn];
int size;
long long ans; bool Less(int loc) {
int cur = sa[loc];
for (int i = ; i < size; i++) {
if (d[cur] < p[i]) return true;
if (d[cur] > p[i]) return false;
cur++;
if (cur == n)
if (i == size - ) return false;
else return true;
}
return false;
} bool lessEqual(int loc) {
int cur = sa[loc];
for (int i = ; i < size; i++) {
if (d[cur] < p[i]) return true;
if (d[cur] > p[i]) return false;
cur++;
if (cur == n)
return true;
}
return true;
} int find() {
if (size == ) return n + ;
int i = , j = n - , mid;
while (i <= j) {
mid = (i + j) >> ;
if (Less(mid)) i = mid + ;
else j = mid - ;
}
int st = i;
i = , j = n - , mid;
while (i <= j) {
mid = (i + j) >> ;
if (lessEqual(mid)) i = mid + ;
else j = mid - ;
}
return i - st;
} void Solve() {
ans = ;
while (m--) {
scanf("%d", &size);
int pre, c;
scanf("%d", &pre);
for (int i = ; i < size - ; i++) {
scanf("%d", &c);
p[i] = Tnode(c / gcd(c, pre), pre / gcd(c, pre));
pre = c;
}
size--;
ans += find();
}
printf("%I64d\n", ans);
} int main() { int t;
scanf("%d", &t);
while (t--) {
Init();
Solve();
}
return ;
}

Funny Game

Time Limit: 2000/1000 MS
(Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 0    Accepted Submission(s): 0

Problem Description

Bob has an array {a1,a2,…,an}, each element is an integer between 1
and n. Bob also has m functions whose domain and codomain are
both {1,2,…,n}. Bob and Alice begin to play a game on
the array. Alice plays first. For each turn, the player can choose a function f and make every ai (1≤in) become f(ai). For example, the array is {1,1,2,4,5} and f(1)=1,f(2)=3,f(3)=4,f(4)=1,f(5)=2. Then after the operation the array
will become {1,1,3,1,2}. If all the element in the array is same, then Alice
wins and the game stops. So you can see that Bob's goal is to stop Alice.
Suppose that both Alice and Bob play optimally. Alice wants to know if she can
always win no matter what the array looks like.

Input

There are multiple test cases. The first
line of input contains an integer T (1≤T≤200), indicating the number of test cases.
For each test case: The first line contains two integers n and m (1≤n,m≤100), indicating the element in the array
and the number of functions. In the next m lines, each contains n integers f(1),f(2),…,f(n) (1≤f(i)≤n,1≤in).

Output

For each case, output "YES"(without
quotes) if Alice can always win no matter what the array looks like, otherwise
output "NO"(without quotes).

Sample Input

2

5 1

1 3 4 1 2

5 1

2 3 4 5 1

Sample Output

YES

NO

Funny Game

Time Limit: 2000/1000 MS
(Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 72    Accepted Submission(s): 2

问题描述

Bob有一个数组{a1,a2,…,an},数组中的每个元素都是介于1到n之间的整数。Bob还有m 个函数,他们的定义域和值域都是集合{1,2,…,n}。 Bob和Alice轮流开始玩游戏,Alice先开始。 对于每一轮,玩家可以选择一个函数f使得数组中每个元素 ai (1≤in)变成f(ai)。例如,一开始数组是{1,1,2,4,5},有一个函数f(1)=1,f(2)=3,f(3)=4,f(4)=1,f(5)=2。那么经过一次操作,数组变为{1,1,3,1,2}。如果数组中的所有元素都相同(无论当前论是Bob还是Alice),那么Alice胜利游戏结束。然后Bob的目的是阻止Alice胜利。 假设Alice和Bob都足够聪明,每次都采取最优策略。问:无论数组的初始状态是什么,Alice是否都能够必胜?

输入描述

输入第一行包含一个整数T (1≤T≤200)表示测试数据组数。对于每组测试数据:第一行包含两个整数nm (1≤n,m≤100)表示数组的大小和函数的个数。接下来m行,每行包含n个整数f(1),f(2),…,f(n) (1≤f(i)≤n,1≤in)。

输出描述

对于每组数据,如果Alice一定能够必胜,输出YES,否则输出NO。

输入样例

2

5 1

1 3 4 1 2

5 1

2 3 4 5 1

输出样例

YES

NO

最后15分钟才看这题,一开始意思理解错了。。。。。悲剧!

看到这道题的第一感觉是博弈。。。可惜没时间做了,还有好像生疏了。/惨。

还有关键的一句话没理解;


#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std; int f[][];
int flag[];
int father[]; int Find(int x) //找到x家族祖先并搜索路径上的成员都指向祖先
{
return x==father[x] ? x : father[x]=Find(father[x]);
} void Union(int a,int b) //b家族并入a家族,b祖先指向a祖先
{
if(a!=b)
father[b]=a;
} int main()
{
int T,n,m,i,j,k;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
memset(flag,,sizeof(flag)); for(i=;i<=n;i++)
father[i]=i; for(i=;i<=m;i++)
{
for(j=;j<=n;j++)
{
scanf("%d",&f[i][j]);
if(f[i][j]==j)
{
flag[j]++;
}
}
}
int cnt=;
for(k=;k<=n;k++)
{
// printf("%d\t",flag[k]);
if(flag[k]==m)
{
cnt++;
}
}
// printf("\ncnt=%d\n",cnt);
if(cnt==)
{
for(i=;i<=m;i++)
{
for(j=;j<=n;j++)
{
if(father[j]==j)
Union(Find(f[i][j]),Find(father[j])); //输入一组合并一组
// printf("%d",)
}
}
for(i=,k=;i<=n;i++)
{
// printf("father[%d]=%d\n",i,father[i]);
if(father[i]==i)k++; }
if(k==)
printf("YES\n");
else
printf("NO\n");
}
else
printf("NO\n");
}
return ;
}
/* 20
5 1
1 3 4 1 2
5 1
2 3 4 5 1
5 1
2 3 4 4 2
8 3
2 3 4 5 5 6 6 7
5 3 2 4 5 7 8 8
1 2 3 4 5 4 8 7
8 2
2 3 4 5 5 6 6 7
5 3 2 4 5 7 8 8 */

思路有问题,不要看喽。很搓!

大神做的:

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>
#define Max(a, b) ((FASTBUFFER = ((a) - (b)) >> 31), ((b) & FASTBUFFER | (a) & ~FASTBUFFER))
#define Min(a, b) ((FASTBUFFER = ((a) - (b)) >> 31), ((a) & FASTBUFFER | (b) & ~FASTBUFFER))
#define Swap(a, b) (a ^= b, b ^= a, a ^= b)
#define OO 2147483647
#define priority_queue PQ
#define pb push_back
#define mp make_pair using namespace std; int FASTBUFFER; const int N = ; int test, n, m;
int f[N][N], ok[N][N], visit[N][N][], deg[N][N];
vector <pair <int, int> > e[N][N];
int hashCnt, hashNow[N][N];
queue <pair <pair <int, int>, int> > q; void work() {
scanf("%d %d", &n, &m);
for (int i = ; i <= m; i++) {
for (int j = ; j <= n; j++) {
scanf("%d", &f[i][j]);
}
} for (int i = ; i <= n; i++) {
for (int j = ; j <= n; j++) {
ok[i][j] = ;
for (int k = ; k <= m; k++) {
if (f[k][i] == f[k][j]) {
ok[i][j] = ;
break;
}
}
}
} for (int i = ; i <= n; i++) {
for (int j = i; j <= n; j++) {
deg[i][j] = ;
visit[i][j][] = ;
visit[i][j][] = ok[i][j];
e[i][j].clear();
}
} for (int i = ; i <= n; i++) {
for (int j = i; j <= n; j++) {
hashCnt++;
for (int k = ; k <= m; k++) {
int c = f[k][i], d = f[k][j];
int a = min(c, d), b = max(c, d);
if (hashNow[a][b] != hashCnt) {
hashNow[a][b] = hashCnt;
deg[i][j]++;
e[a][b].pb(mp(i, j));
}
}
}
} while (q.size()) {
q.pop();
} for (int i = ; i <= n; i++) {
for (int j = i; j <= n; j++) {
if (!deg[i][j]) {
q.push(mp(mp(i, j), ));
visit[i][j][] = ;
} if (ok[i][j]) {
q.push(mp(mp(i, j), ));
visit[i][j][] = ;
}
}
} while (q.size()) {
int a = q.front().first.first, b = q.front().first.second, c = q.front().second;
q.pop();
if (c == ) {
for (int x = ; x < (int)e[a][b].size(); x++) {
int a1 = e[a][b][x].first, b1 = e[a][b][x].second;
if (visit[a1][b1][] == ) {
visit[a1][b1][] = ;
q.push(mp(mp(a1, b1), ));
}
}
} else {
for (int x = ; x < (int)e[a][b].size(); x++) {
int a1 = e[a][b][x].first, b1 = e[a][b][x].second;
deg[a1][b1]--;
if (visit[a1][b1][] == && deg[a1][b1] == ) {
visit[a1][b1][] = ;
q.push(mp(mp(a1, b1), ));
}
}
}
} for (int i = ; i < n; i++) {
for (int j = i; j <= n; j++) {
if (visit[i][j][] == ) {
printf("NO\n");
return;
}
}
} printf("YES\n");
} int main() {
//freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout);
scanf("%d", &test);
while (test--) {
work();
} return ;
}
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<string>
#include<iostream>
#include<sstream>
#include<set>
#include<map>
#include<queue>
#include<bitset>
#include<vector>
#define SZ(X) ((int)(X).size())
#define ALL(X) (X).begin(), (X).end()
#define REP(I, N) for (int I = 0; I < (N); ++I)
#define REPP(I, A, B) for (int I = (A); I < (B); ++I)
#define RI(X) scanf("%d", &(X))
#define RII(X, Y) scanf("%d%d", &(X), &(Y))
#define RIII(X, Y, Z) scanf("%d%d%d", &(X), &(Y), &(Z))
#define DRI(X) int (X); scanf("%d", &X)
#define DRII(X, Y) int X, Y; scanf("%d%d", &X, &Y)
#define DRIII(X, Y, Z) int X, Y, Z; scanf("%d%d%d", &X, &Y, &Z)
#define RS(X) scanf("%s", (X))
#define CASET int ___T, case_n = 1; scanf("%d ", &___T); while (___T-- > 0)
#define MP make_pair
#define PB push_back
#define MS0(X) memset((X), 0, sizeof((X)))
#define MS1(X) memset((X), -1, sizeof((X)))
#define LEN(X) strlen(X)
#define F first
#define S second
typedef long long LL;
using namespace std;
const int MOD = 1e9+;
const int SIZE = ;
int a[SIZE],deg[SIZE*SIZE],used[SIZE][SIZE][];
int n,m,tt;
vector<int>e[SIZE*SIZE];
int get(int x,int y){
if(x>y)swap(x,y);
return x*n+y;
}
int main(){
CASET{
tt++;
RII(n,m);
REP(i,n*n)e[i].clear(),deg[i]=;
REP(i,m){
REP(j,n){
RI(a[j]);
a[j]--;
}
REP(j,n)REPP(k,j+,n){
e[get(a[j],a[k])].PB(get(j,k));
}
}
REP(i,n*n){
sort(ALL(e[i]));
e[i].resize(unique(ALL(e[i]))-e[i].begin());
if(i%n!=i/n)
REP(j,SZ(e[i]))deg[e[i][j]]++;
} queue<int>qq;
REP(i,n){
used[i][i][]=tt;
qq.push(i);
qq.push(i);
}
REP(i,n)REPP(j,i+,n){
int me=get(i,j);
if(deg[me]==){
used[i][j][]=tt;
qq.push(i);
qq.push(j);
}
}
while(!qq.empty()){
int x=qq.front();qq.pop();
int y=qq.front();qq.pop();
int me=get(x,y);
REP(i,SZ(e[me])){
int nx=e[me][i]/n;
int ny=e[me][i]%n;
if(used[nx][ny][]!=tt){
used[nx][ny][]=tt;
int you=get(nx,ny);
REP(j,SZ(e[you])){
int nnx=e[you][j]/n;
int nny=e[you][j]%n;
int he=get(nnx,nny);
deg[he]--;
if(!deg[he]){
qq.push(he/n);
qq.push(he%n);
used[he/n][he%n][]=tt;
}
}
}
}
}
bool lose=;
REP(i,n)REPP(j,i+,n){
if(used[i][j][]!=tt){
lose=;
}
}
if(lose)puts("NO");
else puts("YES");
}
return ;
}

官方解题报告:

1001 Jump and Jump...

首先算出每个人的成绩,然后sort一下就好了,考虑n的范围只有2或者3,只要用if+swap也是可行的。

1002 Taking Bus

简单的分类讨论,设s,x,y分别表示公交的始发站,起点和终点。大概有这样几种情况:1. s≤x<y, 2. x<s<y,3. x<y≤s, 4. s≤y<x, 5. y<s<x, 6. y<x≤s

分别写出公式即可。答案应该会超过int,注意要用long long。

1003 Matching on Array

首先我们考虑m=1的情况。给定两个数组A={a1,a2,…,an}和B={b1,b2,…,bk},问B在A中出现了几次。令ci=ai+1ai,1≤i<n,同样令di=bi+1bi,1≤i<k,那么上述问题可以转化为ci和di的模式匹配问题,这个正确性显然,也没有什么好证明的。于是对于m=1的情况只有用个kmp即可搞定。

现在考虑m>1的情况,我们考虑用ac自动机来做。考虑到字符集并不是普通的数字,而是一个分数,我们不放搞个分数类,然后用map存转移边。用m个模式串(Bob的序列)建好自动机之后,把文本串(Alice的序列)在自动机上跑一遍即可统计出答案。

1004 Funny Game

题目要求对于任何初始状态都要必胜,我们先把这个条件简化一下,毕竟我们不可能枚举所有的初始状态(总共n!个)。

我们先考虑{1,2,…,n}这个状态的必胜条件——对于任意一对数(x,y),1≤x,y≤n, Alice都能都把它们变成相同的数。这个条件也显然是充分必要的,随便想想就明白了。然后我们可以发现,如果{1,2,…,n}这个状态能够必胜的话,其他的状态也显然能够必胜。如果这个状态不能够必胜,那根本不需要考虑其他状态了。

于是我们只需要考虑是否对于任意一对数(x,y),1≤x,y≤n, Alice都能都把它们变成相同的数。这样的状态数只有O(n2)个,我们可以考虑dp来做。先用题目给定的m个函数构造出一张有向图,图中每个节点都是数对。仔细想想就会发现我们不能用普通的博弈思路来做,因为这个博弈会形成环,这时候我们考虑从终结状态往回推,得出每个状态的dp值。

令dp[i][j][0/1]表示数对为(i,j),Alice先(1)后(0)手是否必胜。然后我们知道dp[i][i][0/1]都是必胜的,并把这些状态放入队列。我们依次从队列中取出一个状态(x,y,turn),如果turn=1,那么这个状态的前驱是Bob的回合,不妨设为(a,b,0),那么如果(a,b,0)的后继状态都是Alice必胜的话,那么dp[a][b][0]显然也是Alice必胜的,否则这个状态的值我们目前无法确定。如果turn=0,类似的那么这个状态的前驱是Alice的回合,不妨设为(a,b,1),那么如果(a,b,1)的后继中有一个状态是Alice必胜的,那么dp[a][b][1]显然也是Alice必胜,考虑到(x,y,0)就是Alice必胜的,那么前驱状态(a,b,1)必然是Alice必胜。我们每次把必胜状态加入队列,用来更新那些未确定的状态。

最后统计是否每个(x,y,1)的状态都是必胜的,如果是那么Alice输出YES,否则输出NO。时间复杂度的话是O(n3)。

这几天状态不佳。要调整!

BestCoder Round #27的更多相关文章

  1. hdu5631 BestCoder Round #73 (div.2)

    Rikka with Graph  Accepts: 123  Submissions: 525  Time Limit: 2000/1000 MS (Java/Others)  Memory Lim ...

  2. hdu5630 BestCoder Round #73 (div.2)

    Rikka with Chess  Accepts: 393  Submissions: 548  Time Limit: 2000/1000 MS (Java/Others)  Memory Lim ...

  3. BestCoder Round #81 (div.2) 1004 String(动态规划)

    题目链接:BestCoder Round #81 (div.2) 1003 String 题意 中文题,上有链接.就不贴了. 思路 枚举起点i,计算能够达到k个不同字母的最小下标j,则此时有子串len ...

  4. BestCoder Round #89 02单调队列优化dp

    1.BestCoder Round #89 2.总结:4个题,只能做A.B,全都靠hack上分.. 01  HDU 5944   水 1.题意:一个字符串,求有多少组字符y,r,x的下标能组成等比数列 ...

  5. BestCoder Round #90 //div all 大混战 一题滚粗 阶梯博弈,树状数组,高斯消元

    BestCoder Round #90 本次至少暴露出三个知识点爆炸.... A. zz题 按题意copy  Init函数 然后统计就ok B. 博弈 题  不懂  推了半天的SG.....  结果这 ...

  6. bestcoder Round #7 前三题题解

    BestCoder Round #7 Start Time : 2014-08-31 19:00:00    End Time : 2014-08-31 21:00:00Contest Type : ...

  7. Bestcoder round #65 && hdu 5593 ZYB's Tree 树形dp

    Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submissio ...

  8. Bestcoder round #65 && hdu 5592 ZYB's Premutation 线段树

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submissio ...

  9. 暴力+降复杂度 BestCoder Round #39 1002 Mutiple

    题目传送门 /* 设一个b[]来保存每一个a[]的质因数的id,从后往前每一次更新质因数的id, 若没有,默认加0,nlogn复杂度: 我用暴力竟然水过去了:) */ #include <cst ...

随机推荐

  1. WPF 触摸屏小键盘样式

    WPF程序,用于平板时,一些输入数量的地方我们需要弹出小键盘输入,这个键盘可以调系统的,也可以自己写. 分享个我现在用的一个数字键盘界面. <Window xmlns:dxe="htt ...

  2. .net图表之ECharts随笔04-散点图

    见图说话,修改参数option实现上图显示: 1. 共用参数title还有一个属性subtext,可以用来设置副标题 2. tooltip与toolbox也是共用属性 3. dataZoom是设置滚动 ...

  3. SpringBoot启动过程分析

    我们知道,SpringBoot程序的启动很简单,代码如下: @SpringBootApplication public class Application { public static void m ...

  4. Node学习笔记---初识Node

    博客原文地址:Claiyre的个人博客 https://claiyre.github.io/ 博客园地址:http://www.cnblogs.com/nuannuan7362/ 如需转载,请在文章开 ...

  5. solr初识

    参考资料http://blog.csdn.net/l1028386804/article/details/70199983

  6. Python staticmethod classmethod 普通方法 类变量 实例变量 cls self 概念与区别

    类变量 1.需要在一个类的各个对象间交互,即需要一个数据对象为整个类而非某个对象服务. 2.同时又力求不破坏类的封装性,即要求此成员隐藏在类的内部,对外不可见. 3.有独立的存储区,属于整个类.   ...

  7. odoo-开发笔记 列表视图 增加记录弹出窗口效果

    editable="bottom" 增加该标签的效果是,添加记录的时候,在原列表视图上一行一行添加; 去掉该标签之后,那么增加新记录的时候,会以弹出窗口的方式实现. 如果弹出的窗口 ...

  8. Java获取随机数获取制定范围指定个数不重复的随机数

    一.JDK中提供的两种方式 1.Math类中的random()方法public static double random()返回带正号的 double 值,该值大于等于 0.0 且小于 1.0 [0. ...

  9. 广度优先遍历-BFS、深度优先遍历-DFS

    广度优先遍历-BFS 广度优先遍历类似与二叉树的层序遍历算法,它的基本思想是:首先访问起始顶点v,接着由v出发,依次访问v的各个未访问的顶点w1 w2 w3....wn,然后再依次访问w1 w2 w3 ...

  10. OwinHost

    新建ASP.NET MVC 项目. 引用包: install-package Microsoft.Owin.Host.SystemWeb 修改 public class Startup { publi ...