A.Trape
背景 :
一个平面上有许多点,LYH需要在这个平面上画一个等腰梯形,LYH希望在这个梯形内的点尽可能得多,LYH让你帮她求梯形内最大点数。(点在梯形边上也算梯形内)
题目描述 :
给出M个点求用一个上底长25,下底长75,高50的等腰梯形最多能框住的点数。
输入格式 :
第一行两个正整数N,M,N表示横坐标在[-N,N],纵坐标在[-N,N]的平面大小, M表示点数。 接下来M行,每行两个整数x,y,为各个点的横纵坐标。
输出格式 :
一行一个正整数为最大点数。
数据范围 :
60% N<=150
80% M<=300
90% M<=3000
100% N<=2500 M<=10000 -N<=x,y<=N
Solution :
题意没写清楚,这个梯形一定是上下底平行于x轴且是正的(上底在上面)。
可以枚举底边左端点所在的纵坐标 \(m\),然后对于每个点\((x[i],y[i])\) 将它们分别对应到 \(y=m\) 上(在 \(x[i]-(y[i] + m)/2\)处 \(-1\),在 \(x[i]+(y[i]-m)/2-75\) 处 \(+1\) ,表示在该位置有一个点进入或退出梯形),然后求一个最大的前缀和即可
Code :
#pragma GCC optimize(3,"Ofast","inline") #include<bits/stdc++.h> #define max(x,y) (x>y?x:y) #define mp make_pair #define fi first #define se second using namespace std; typedef pair<int, int> pii; const int N = 10005; int n, m, x[N], y[N]; pii p[N * 2]; inline bool cmp(pii u, pii v) { return u.fi < v.fi || (u.fi == v.fi && u.se > v.se); } template<typename T> void read(T &x) { bool f = false; x = 0; char ch = getchar(); while (ch<'0' || ch>'9') {if (ch == '-') f = true; ch = getchar();} while (ch>='0' && ch<='9') x = x * 10 + ch - '0', ch = getchar(); if (f) x = -x; } int main() { read(n), read(m); for (int i = 1; i <= m; i++) { read(x[i]), read(y[i]); } int ans = 0; for (int i = -n; i <= n; i++) { int cnt = 0; for (int j = 1; j <= m; j++) { if (y[j] < i || y[j] - i > 50) continue; //因为坐标差除2可能出现小数所以都*2 p[++cnt] = mp(2 * x[j] - y[j] + i, -1); //-1的位置不需要后移一位,只要排序时让+1在前,那么处理该位置就会先进入在退出 p[++cnt] = mp(2 * x[j] + y[j] - i -150, 1); } sort(p + 1, p + 1 + cnt, cmp); int now = 0; for (int j = 1; j <= cnt; j++) { now += p[j].se; ans = max(ans, now); } } printf("%d\n", ans); return 0; }
B.Rcomb
题目描述 :
Na老师有\(N\)张卷子排成一列,第i张卷子有其难度\(V_i\),由于X爷的出现,Na老师需要将这些卷子合并为1张。每次Na老师以相等的概率随机选择两张相邻卷子,消耗两张卷子难度和的体力,得到一张难度为两张卷子难度和的卷子,求 Na老师需要消耗的体力期望值。
输入格式 :
第一行:一个整数\(N\)。
第二行:\(N\)个整数\(V_1、V_2、...、V_N\)。
输出格式 :
只有一行,一个小数ANS(小数点后保留5位)表示Na老师需要消耗的体力期望值。
数据范围 :
30% N<=10
60% N<=100
100% 1<=N<=5000 1<=V_i<=10000
Solution & Code :
#include<bits/stdc++.h> using namespace std; const int N = 5005; int n, a[N]; double dp[2][N]; // dp[i][j] 表示长度为i的序列排在第j位的试卷的期望被计入的次数 // dp[1][1] = 0 长度为 1 没有合并 次数为 0 template<typename T> void read(T &x) { bool f = false; x = 0; char ch = getchar(); while (ch<'0' || ch>'9') {if (ch == '-') f = true; ch = getchar();} while (ch>='0' && ch<='9') x = x * 10 + ch - '0', ch = getchar(); if (f) x = -x; } int main() { read(n); for (int i = 1; i <= n; i++) read(a[i]); // dp[0][0] = 0; dp[1][1] = 0; for (int i = 2; i <= n; i++) { for (int j = 1; j <= i; j++) { if (j > 1) dp[i&1][j] += dp[(i-1) & 1][j-1] * (j-1) / (i-1) + 1.0 / (i-1); //因为每相邻两试卷有相同概率被合并,所以每次合并的期望贡献次数为 1.0/(i-1) if (j < i) dp[i&1][j] += dp[(i-1) & 1][j] * (i-j) / (i-1) + 1.0 / (i-1); } memset(dp[(i-1) & 1], 0, sizeof(dp[(i-1) & 1])); } double ans = 0; for (int i = 1; i <= n; i++) { ans += dp[n&1][i] * a[i]; } cout<< fixed << setprecision(5) << ans << endl; return 0; }
C.Game
题目描述 :
给出一个由小写英文字母构成的字符串 S,再取 n 个字符串,它们都是 S 的子串,之后开始游戏,两人轮流操作: 每次选一个串,在其后添加一个英文字母,保证添加后该串仍为 S 的子串。 谁不能操作谁输,或者谁不能操作谁胜。 但是春希看出了胜负已定,于是对实际操作没有兴趣,所以 Pickupwin 只要求他指明先手是否必胜就好。
输入格式 :
第一行一个字符串 S;
第二行一个正整数 n;
接下来 n 行,每行两个正整数 l,r,表示第 i 个字符串由 S 中第 l 个至第 r 个字符一次拼接而成(S 中字符从 1 开始标号)
输出格式 :
输出 n + n行
第 \(2 * i - 1\) 行输出在仅有前 i 个子串时,谁不能操作谁输,先手是否必胜。
第 \(2 * i\) 行输出在仅有前 i 个子串时,谁不能操作谁胜,先手是否必胜。
用 Fir 表示先手必胜, Sec 表示后手必胜。
样例 :
输入 :
sroababorz 3 4 5 7 8 1 3
输出 :
Fir Sec Fir Sec Sec Fir
数据范围 :
50% |S| <= 200,n <= 100
100% |S| <=\(10^6\), n <= \(5*10^5\)