前言
没有前言。
挂盘子
输入样例
3 10
1 2 3
输出样例
68
题解(组合数学+求逆元+递推)
这题我考试时没做出来,后来看了题解。
题解中的 (ji) 是 Cij 的意思,其他都是基础的组合数学,我就不再赘述了。
另外题解中的递推求组合数也可以改成厉害的分块打表(反正我不会),求逆元也可以不用费马小定理,改用Exgcd也行。
需要吐槽的是这题数据错了,搞的我一直过不了,只有40分,其实是标程写错了,rt。。
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <iostream>
#define N 4005
#define M 200005
#define Mod 1000000007
using namespace std;
typedef long long LL;
int n, m, r[N], tot, A[M];
LL f[N], C, ans;
LL Pow(LL x, LL y){
LL ans = 1LL;
while(y){
if(y & 1) ans = ans * x % Mod;
x = x * x % Mod;
y >>= 1;
}
return ans;
}
int main(){
scanf("%d%d", &n, &m);
f[0] = 1LL;
for(int i = 1; i <= n; i++){
scanf("%d", &r[i]);
tot += (r[i] << 1);
f[i] = f[i-1] * i % Mod;
}
for(int i = 1; i < n; i++)
for(int j = i+1; j <= n; j++)
if(tot-r[i]-r[j] <= m) A[r[i]+r[j]] += 2;
for(int i = 2; i < M; i++){
if(A[i]){
if(!C){
C = Pow(f[n], Mod-2LL);
for(int j = 1; j <= n; j++) C = C * (m-tot+i+j) % Mod;
}
ans = (ans + A[i] * C % Mod * f[n-2] % Mod) % Mod;
}
if(C) C = C * (m-tot+i+n+1) % Mod * Pow(m-tot+i+1, Mod-2LL) % Mod;
}
printf("%lld\n", ans);
return 0;
}
晚会
输入样例
5
2
0 1
2
1 0
4
1 0 3 2
6
5 2 2 4 5 0
6
3 2 1 0 5 4
输出样例
2
1
2
5
3
题解(找几个环)
这题才是本场比赛的签到题。我一拿到题目先做的是第三题,过了不到20min,就有人第二题有分数了,我立刻意识到第二题肯定很水。其实题目很简单,就是给你一幅图,里面有一些树,一些环,还有环套树之类的,如果是树的话,我们从叶子向上邀请奶牛们就行了,如果发现一个环的话,肯定有一头奶牛要舍弃,于是答案就是 n−ans , ans 就是环的数量。
是不是很水啊,不过20min内提交的那几个人好像都爆10了=。=
时间 O(n2) 。
代码
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <iostream>
#define MAXN 60
using namespace std;
int R;
int n, ans;
int hate[MAXN];
bool vis[MAXN], used[MAXN];
int main(){
scanf("%d", &R);
while(R --){
scanf("%d", &n);
for(int i = 0; i < n; i++)
scanf("%d", &hate[i]);
memset(used, false, sizeof(used));
ans = 0;
for(int i = 0; i < n; i++){
if(used[i] || hate[i] == i) continue;
int j = i;
do{
vis[j] = true;
j = hate[j];
}while(!vis[j]);
if(j == i){
ans ++;
for(int k = 0; k < n; k++)
used[k] |= vis[k];
}
j = i;
do{
vis[j] = false;
j = hate[j];
}while(vis[j]);
}
printf("%d\n", n - ans);
}
return 0;
}
不得右转
题目描述
Roger和Robot被送到一个星球上。星球的表面可以想象成二维平面。现在给你x数组和y数组,每一组(x[i], y[i])表示一个点。没有三点共线的情况。
Roger会选择{0, 1, …, N – 1}的一个排列,然后按照排列的顺序访问这些点。Roger从一个点到另一个点是走直线段的。他会遵守两个条件:
1.他走的路线不能相交。(如果我们把他走的线段画出来,没有两条线段在非端点的位置相交)
2.从来都不右转。这意味着任意连续三点一定按照逆时针顺序。
你现在的任务是为Roger找一条路线。如果没有这样的路线,请输出0,和一个空行;否则分两行分别输出N和访问的路线(输出点的编号)。
输入格式
多组测试数据。第一行是测试数据组数。
对于每组数据,第一行为N,接下来分别是x数组和y数组(坐标都为整数)。
【限制】
2≤N≤50
-1000 ≤ x[i], y[i] ≤ 1000
点没有重合的
输出格式
对于每组数据输出两行,如题。
输入样例
5
3
-10 0 10
10 -10 10
6
0 0 -3 -3 3 3
-1 1 -3 3 -3 3
10
10 9 8 7 6 5 4 3 2 1
1 4 9 16 25 36 49 64 81 100
8
0 2 -2 4 -4 2 -2 0
1 2 2 4 4 6 6 5
41
-443 887 -16 -388 -245 652 758 640 589 -75 -827 -428 344 -920 -340 -80 -753 546 202 701 -323 804 -603 452 495 -956 -628 417 798 -666 -542 363 11 -558 -466 166 -645 -568 886 902 -933
12 -220 -421 176 -21 -419 -55 8 -12 -278 -7 12 -27 -615 26 -408 -559 -17 -60 -3 79 15 -11 7 -22 -3 83 1 -69 6 -1 485 26 -1 -812 -430 -58 70 403 1 300
输出样例
3
0 1 2
6
0 4 5 3 2 1
10
9 8 7 6 5 4 3 2 1 0
8
4 2 0 1 3 5 6 7
41
27 24 17 8 23 32 14 12 6 19 7 20 11 4 18 28 21 3 0 5 1 39 38 31 40 25 13 34 35 37 26 10 16 2 9 30 29 36 15 33 22
【样例解释】
样例1:
The points form a triangle. Any of the following return values will be accepted: {0,1,2},{1,2,0},{2,0,1}
样例2:
Here is a picture of the points:
Here is an example of a different valid solution. This would correspond to a return value of {1,5,3,2,4,0}
本题有SPJ。
题解(求几个凸包/叉积/斜率+模拟)
题解后面那堆文字请自行忽略。
我看完这题的题目,计算几何啊啊啊!然而考试结束后我才码出来。
考试时不在状态,码来码去总是心态爆炸,调试也调不出来。
其实这题就是裸的求凸包题。
我的麻烦的方法就是每次从外到内求凸包,然后模拟从外向里走就行了。
没有0的情况。
另外的方法就是用凸包的思想,不过不用每次从外到内做扫描法求凸包,直接将卷包裹法变一下,有人就是这么做的。卷包裹每次要求所有点都在其线同侧,而这题只用左转,所以需要剩下的点在左侧就够了,不断模拟路径,同时这样保证能走完所有的点(共线也要走)。这种方法比上面我的方法要快,而且。。好写多了。。
如何做卷包裹又分为两种,首先找到最边边的点后,再找点,然后使得所有点在其有向连线左边(直接枚举两条边也可以)。一种方法就是叉积找,其实用斜率也可以,直接 O(n) 找最小斜率,跟用叉积判断左右是一样的。
以上的方法殊途同归,本质上都是凸包的变种。
我的码代码的能力还需要急剧提升,不然像计算几何、数据结构这样的码农题,考试时想到但调不出来只能束手无策。
代码
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <cassert>
#define N 60
#define INF 1e9
using namespace std;
int nG, n, m;
struct Point{
int x, y, id;
Point() {}
Point(int _x, int _y):x(_x), y(_y) {}
bool operator < (const Point& P) const{
if(x == P.x) return y < P.y;
return x < P.x;
}
friend Point operator + (Point A, Point B){return Point(A.x + B.x, A.y + B.y);}
friend Point operator - (Point A, Point B){return Point(A.x - B.x, A.y - B.y);}
};
int Det(Point A, Point B){return A.x * B.y - A.y * B.x;}
bool used[N];
Point p[N], Con[N][N];
int Cnt[N], s[N];
void Get_Convex(int id){
sort(p, p+n);
int res = 0;
for(int i = 0; i < n; i++)
if(p[i].x == INF && p[i].y == INF) res ++;
n -= res;
Cnt[id] = 0;
for(int i = 0; i < n; i++){
while(Cnt[id] > 1 && Det(p[i] - Con[id][Cnt[id]], Con[id][Cnt[id]] - Con[id][Cnt[id]-1]) > 0) Cnt[id] --;
Con[id][++Cnt[id]] = p[i];
}
int k = Cnt[id];
for(int i = n-2; i >= 0; i--){
while(Cnt[id] > k && Det(p[i] - Con[id][Cnt[id]], Con[id][Cnt[id]] - Con[id][Cnt[id]-1]) > 0) Cnt[id] --;
Con[id][++Cnt[id]] = p[i];
}
if(n != 1) Cnt[id] --;
for(int i = 1; i <= Cnt[id]; i++)
used[Con[id][i].id] = true;
for(int i = 0; i < n; i++)
if(used[p[i].id]) p[i].x = p[i].y = INF;
}
bool Check(){
bool ok = true;
for(int i = 0; i < m && ok; i++) if(!used[i]) ok = false;
return ok;
}
int main(){
scanf("%d", &nG);
while(nG --){
scanf("%d", &n);
m = n;
for(int i = 0; i < n; i++)
scanf("%d", &p[i].x);
for(int i = 0; i < n; i++)
scanf("%d", &p[i].y);
for(int i = 0; i < n; i++)
p[i].id = i;
memset(Cnt, 0, sizeof(Cnt));
memset(used, false, sizeof(used));
int id;
for(id = 1; ;id ++){
if(Check()) break;
Get_Convex(id);
}
id --;
s[1] = 1;
for(int i = 1; i < id; i++){
bool f = false;
for(int j = 1; j <= Cnt[i+1] && !f; j++){
bool ok = true;
Point A = Con[i][(s[i]-1)?s[i]-1:Cnt[i]], B = Con[i+1][j];
for(int u = 1; u <= Cnt[i+1]; u++)
if(Det(B - A, Con[i+1][u] - A) < 0){
ok = false;
break;
}
if(ok){
s[i+1] = j;
f = true;
}
}
}
printf("%d\n", m);
for(int i = 1; i <= id; i++){
printf("%d ", Con[i][s[i]].id);
for(int j = s[i]+1; j <= Cnt[i]; j++)
printf("%d ", Con[i][j].id);
for(int j = 1; j < s[i]; j++)
printf("%d ", Con[i][j].id);
}
printf("\n");
}
return 0;
}
总结
这场比赛考得很糟糕,第三题有人A掉我却调不出来,第一题也没有去水分。希望重要的考试的时候不要犯一些不该犯的错误,不要留下什么遗憾。
此生无悔入四月,来世愿做友人A。