当前位置:网站首页>SCUACM22暑假集训前劝退赛部分题解
SCUACM22暑假集训前劝退赛部分题解
2022-06-12 15:16:00 【hans774882968】
传送门
作者:hans774882968以及hans774882968
A
简单几何题,用三角函数知识很容易推(对于考上SCU的同学)。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,b) for(int i = (a);i <= (b);++i)
#define re_(i,a,b) for(int i = (a);i < (b);++i)
#define dwn(i,a,b) for(int i = (a);i >= (b);--i)
const int N = 1e6 + 5;
int r, a, b, h;
void dbg() {
puts ("");
}
template<typename T, typename... R>void dbg (const T &f, const R &... r) {
cout << f << " ";
dbg (r...);
}
template<typename Type>inline void read (Type &xx) {
Type f = 1;
char ch;
xx = 0;
for (ch = getchar(); ch < '0' || ch > '9'; ch = getchar() ) if (ch == '-') f = -1;
for (; ch >= '0' && ch <= '9'; ch = getchar() ) xx = xx * 10 + ch - '0';
xx *= f;
}
void read() {
}
template<typename T, typename ...R>void read (T &x, R &...r) {
read (x);
read (r...);
}
int main() {
read (r, a, b, h);
if (2 * r <= b) {
puts ("Drop");
return 0;
}
double H = 1.0 * h * a / (a - b);
double theta = atan (1.0 * a / 2 / H);
printf ("Stuck\n%.10lf\n", r / sin (theta) - b / (2 * tan (theta) ) );
return 0;
}
B
一看就是博弈dp。先打个表
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,b) for(int i = (a);i <= (b);++i)
#define re_(i,a,b) for(int i = (a);i < (b);++i)
#define dwn(i,a,b) for(int i = (a);i >= (b);--i)
const int N = 5e3 + 5;
int dp[N][N], a[N];
int n, m;
void dbg() {
puts ("");
}
template<typename T, typename... R>void dbg (const T &f, const R &... r) {
cout << f << " ";
dbg (r...);
}
template<typename Type>inline void read (Type &xx) {
Type f = 1;
char ch;
xx = 0;
for (ch = getchar(); ch < '0' || ch > '9'; ch = getchar() ) if (ch == '-') f = -1;
for (; ch >= '0' && ch <= '9'; ch = getchar() ) xx = xx * 10 + ch - '0';
xx *= f;
}
void read() {
}
template<typename T, typename ...R>void read (T &x, R &...r) {
read (x);
read (r...);
}
bool dfs (int x, int y) {
if (~dp[x][y]) return dp[x][y];
dp[x][y] = false;
if (! (x + y) ) return dp[x][y] = false;
if (!x || !y) return dp[x][y] = true;
if (x == y) return dp[x][y] = true;
if (x < y) return dp[x][y] = dfs (y, x);
rep (k1, 1, x) {
for (int k2 = 0; k2 <= y; k2 += k1) {
dp[x][y] |= !dfs (x - k1, y - k2);
if (dp[x][y]) break;
}
}
rep (k1, 1, y) {
for (int k2 = 0; k2 <= x; k2 += k1) {
dp[x][y] |= !dfs (x - k2, y - k1);
if (dp[x][y]) break;
}
}
return dp[x][y];
}
void bf (int n) {
memset (dp, -1, sizeof dp);
rep (i, 0, n) rep (j, 0, n) dfs (i, j);
// rep (i, 0, n) rep (j, 0, n) cout << dp[i][j] << " \n"[j == n];
rep (i, 0, n) rep (j, 0, n) if (!dp[i][j]) dbg (i, j);
puts ("");
rep (i, 0, n) rep (j, 0, n) if (!dp[i][j] && i < j) dbg (i, j);
}
int main() {
bf (300);
// memset (dp, -1, sizeof dp);
// int lim = 500;
// rep (i, 1, lim) {
// if (a[i]) continue;
// rep (j, i + 1, lim) {
// if (!dfs (i, j) ) {
// a[i] = j;
// break;
// }
// }
// if (a[i]) a[a[i]] = i;
// if (i % 100 == 0) cout << "i=" << i << endl; //dbg
// }
// rep (i, 1, lim) cout << a[i] << " \n"[i == lim];
return 0;
}
发现每一行至多一个false,但没有发现其他规律。因此有一种做法是跑上面那段被注释的代码,把每一行的false的点(可能不存在)给找出来。但是要等很久,算了。
正解是:既然为false的点不超过5000,那么就直接用刷表法。根据博弈dp常识,值为true的点推不出任何点,值为false的点可以推出一系列值为true的点。根据调和级数,复杂度O(n^2*logn)。说实话这是我第一次看到这种套路。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,b) for(int i = (a);i <= (b);++i)
#define re_(i,a,b) for(int i = (a);i < (b);++i)
#define dwn(i,a,b) for(int i = (a);i >= (b);--i)
const int N = 5e3 + 5;
bool dp[N][N];
int n, m;
void dbg() {
puts ("");
}
template<typename T, typename... R>void dbg (const T &f, const R &... r) {
cout << f << " ";
dbg (r...);
}
template<typename Type>inline void read (Type &xx) {
Type f = 1;
char ch;
xx = 0;
for (ch = getchar(); ch < '0' || ch > '9'; ch = getchar() ) if (ch == '-') f = -1;
for (; ch >= '0' && ch <= '9'; ch = getchar() ) xx = xx * 10 + ch - '0';
xx *= f;
}
void read() {
}
template<typename T, typename ...R>void read (T &x, R &...r) {
read (x);
read (r...);
}
void init (int n) {
rep (i, 0, n) rep (j, 0, n) {
if (dp[i][j]) continue;
rep (k1, 1, n - i) {
for (int k2 = 0; j + k2 <= n; k2 += k1) {
dp[i + k1][j + k2] = true;
}
}
rep (k1, 1, n - j) {
for (int k2 = 0; i + k2 <= n; k2 += k1) {
dp[i + k2][j + k1] = true;
}
}
}
}
int main() {
init (5000);
int T;
read (T);
while (T--) {
read (n, m);
puts (dp[n][m] ? "Alice" : "Bob");
}
return 0;
}
E
设dp[i]为当前得到的数集的最大值为i,能走的步数的期望。再设ans[i]表示当前得到的数集的最大值为i,能获得的分数的期望。因为题目中,分数只获得1次,所以我们假设当前存在一个数集的最大值,但并没有拿过分数。显然这一构造性假设是合法的。
没有数,就用“有一个0”来表示,于是ans[0]即所求。
值得注意的是,我们也可以用数学形式E(x[i])和E(x[i] ^ 2)来表示dp[i]和ans[i]。
推dp
全期望公式:E(X) = sum(E(X|Y = y[i]) * P(Y = y[i]))
设下一个数为j。当下一个数小于i,能走的步数为1;大于等于i,能走的步数为E(1 + x[j]) = 1 + dp[j]。故由全期望公式:
dp[i] = sum(p[j])(j < i) + sum(p[j] * (1 + dp[j]))(j >= i)
移项得:
dp[i] = (1 + sum(p[j] * dp[j])) / (1 - p[i]) (j > i)
推ans
当下一个数小于i,能获得的分数为1。大于等于i,由上述数学形式得E((1 + x[j]) ^ 2) = E(x[j] ^ 2) + 2 * E(x[j]) + 1 = ans[j] + 2 * dp[j] + 1。故由全期望公式:
ans[i] = sum(p[j])(j < i) + sum(p[j] * (ans[j] + 2 * dp[j] + 1))(j >= i)
移项得:
ans[i] = (1 + 2 * dp[i] * p[i] + sum(p[j] * (ans[j] + 2 * dp[j]))) / (1 - p[i]) (j > i)
总结:关注期望dp的数学记号!
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,b) for(int i = (a);i <= (b);++i)
#define re_(i,a,b) for(int i = (a);i < (b);++i)
#define dwn(i,a,b) for(int i = (a);i >= (b);--i)
const int N = 5e3 + 5;
const int mod = 998244353;
LL dp[N], ans[N], p[N];
int a[N];
int n;
void dbg() {
puts ("");
}
template<typename T, typename... R>void dbg (const T &f, const R &... r) {
cout << f << " ";
dbg (r...);
}
template<typename Type>inline void read (Type &xx) {
Type f = 1;
char ch;
xx = 0;
for (ch = getchar(); ch < '0' || ch > '9'; ch = getchar() ) if (ch == '-') f = -1;
for (; ch >= '0' && ch <= '9'; ch = getchar() ) xx = xx * 10 + ch - '0';
xx *= f;
}
void read() {
}
template<typename T, typename ...R>void read (T &x, R &...r) {
read (x);
read (r...);
}
LL q_pow (LL a, LL b) {
LL r = 1;
for (; b; b >>= 1) {
if (b & 1) r = r * a % mod;
a = a * a % mod;
}
return r;
}
int main() {
read (n);
rep (i, 1, n) read (a[i]);
LL isuma = q_pow (accumulate (a + 1, a + n + 1, 0LL), mod - 2);
rep (i, 1, n) p[i] = a[i] * isuma % mod;
dwn (i, n, 0) {
LL s1 = 1, inv1_p = q_pow ( (1 - p[i] + mod) % mod, mod - 2);
rep (j, i + 1, n)
s1 = (s1 + p[j] * dp[j] % mod) % mod;
dp[i] = s1 * inv1_p % mod;
LL s2 = (1 + 2 * p[i] * dp[i] % mod) % mod;
rep (j, i + 1, n)
s2 = (s2 + p[j] * (ans[j] + 2 * dp[j] % mod) % mod) % mod;
ans[i] = s2 * inv1_p % mod;
}
printf ("%lld\n", ans[0]);
return 0;
}
H
a[i]*a[j] = a[k],以及数据范围1e6都提示我们需要枚举倍数。开个桶计数,然后枚举值i和i的倍数j,则贡献为c[i] * c[j] * c[j/i]。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,b) for(int i = (a);i <= (b);++i)
#define re_(i,a,b) for(int i = (a);i < (b);++i)
#define dwn(i,a,b) for(int i = (a);i >= (b);--i)
const int N = 1e6 + 5;
int n, c[N];
void dbg() {
puts ("");
}
template<typename T, typename... R>void dbg (const T &f, const R &... r) {
cout << f << " ";
dbg (r...);
}
template<typename Type>inline void read (Type &xx) {
Type f = 1;
char ch;
xx = 0;
for (ch = getchar(); ch < '0' || ch > '9'; ch = getchar() ) if (ch == '-') f = -1;
for (; ch >= '0' && ch <= '9'; ch = getchar() ) xx = xx * 10 + ch - '0';
xx *= f;
}
void read() {
}
template<typename T, typename ...R>void read (T &x, R &...r) {
read (x);
read (r...);
}
int main() {
read (n);
int mx = 0;
rep (_, 1, n) {
int x;
read (x);
c[x]++;
mx = max (mx, x);
}
LL ans = 0;
rep (i, 1, mx) {
if (!c[i]) continue;
for (int j = i; j <= mx; j += i) {
ans += 1LL * c[i] * c[j] * c[j / i];
}
}
printf ("%lld\n", ans);
return 0;
}
I
签到。
- x是s的子集,x为1的部分随便取,x为0但s为1的部分固定为1。
- x不是s的子集,个数显然为0。
易错点:x == s时0也是答案,但题目问的是正整数,要减掉。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,b) for(int i = (a);i <= (b);++i)
#define re_(i,a,b) for(int i = (a);i < (b);++i)
#define dwn(i,a,b) for(int i = (a);i >= (b);--i)
const int N = 2e5 + 5;
int x, s;
void dbg() {
puts ("");
}
template<typename T, typename... R>void dbg (const T &f, const R &... r) {
cout << f << " ";
dbg (r...);
}
template<typename Type>inline void read (Type &xx) {
Type f = 1;
char ch;
xx = 0;
for (ch = getchar(); ch < '0' || ch > '9'; ch = getchar() ) if (ch == '-') f = -1;
for (; ch >= '0' && ch <= '9'; ch = getchar() ) xx = xx * 10 + ch - '0';
xx *= f;
}
void read() {
}
template<typename T, typename ...R>void read (T &x, R &...r) {
read (x);
read (r...);
}
int main() {
read (x, s);
if (! ( (x & s) == x && (x | s) == s) ) {
puts ("0");
return 0;
}
printf ("%lld\n", (1LL << __builtin_popcount (x) ) - (x == s) );
return 0;
}
边栏推荐
- 应势而变,2022年下半场的升级之路
- 产业端:618的新战场
- [spark][core] what is an external shuffle service?
- Idea pull branch code
- Solve log4j2 vulnerability and be attacked by mining and zombie process viruses
- Xshell 7 official website free download
- Change according to the situation, the road to promotion in the second half of 2022
- 虚拟机中用户和root忘记密码解决办法
- 学习是一件逆人性的事情(成为高手的内功心法)
- Jenkins' RPC test project
猜你喜欢

C escape character
![[jvm learning] local method stack and heap](/img/5d/2e0b758ae52cfdc0d060431df19eea.jpg)
[jvm learning] local method stack and heap

Deepin20.6 rtx3080 installing graphics card drivers 510.60.02, cuda11.6, pytorch1.11

Assertion of selenium webdriver

How to set public IP access on the H3C gr5200 router

Jetpack architecture component learning (3) -- activity results API usage

C main function

Servlet连接数据库实现用户登录功能

Swap numbers, XOR, operator correlation

Deepin20.6 rtx3080 installer le lecteur de carte graphique 510.60.02, cuda 11.6, pytorch1.11
随机推荐
Servlet知识详解(2)
Autofac (2)
频繁项集产生强关联规则的过程
MH32F103ARPT6软硬件兼容替代STM32F103RCT6
C语言打开中文路径文件
IMU learning records
About layoffs in Internet companies
Seaborn的简述
ARM 64指令小记
【无标题】
[jvm learning] class loading subsystem
Alibaba, Tencent and pinduoduo set an example, and the new logic of industrial Internet is gradually emerging
Assertion of selenium webdriver
3D reconstruction system | L3 dual view motion recovery structure (SFM binocular SFM)
[game server design cases] insights
[jvm learning] local method stack and heap
[untitled]
Solve log4j2 vulnerability and be attacked by mining and zombie process viruses
Industrial end: a new battlefield of 618
TCP/IP 三次握手四次挥手(面试题)