比赛传送门
作者: fn
目录
签到题
E题 Rise of Shadows 阴影的升起
题目大意
判断
a
a
a 是否既是闰年又是质数
分析
闰年不可能是质数
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int main(){
ios::sync_with_stdio(0); cin.tie(0);
int t; cin>>t;
while(t--){
cout<<"no"<<endl;
}
return 0;
}
基本题
A题 Ares, Toilet Ares 阿瑞斯,厕所阿瑞斯
题目大意
已知一支队伍能过
a
a
a 道题,有一定概率能过下一题。输出过题数的期望(对4933取模)。
考察内容
乘法逆元
注意
- x = 0 x=0 x=0 时不计入失败概率
- 及时取模
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MOD = 4933;
ll n,m,k,a=1,l,b=1,c,flag=0;
ll x, y;
void exgcd(ll a, ll b)
{
if(b == 0)
{
x = 1;
y = 0;
return;
}
exgcd(b, a % b);
ll Last_x = x;
x = y;
y = Last_x - a / b * y;
}
int main()
{
cin>>n>>m>>k>>c>>l;
for(int i=1;i<=k;i++){
ll x,y,z;
cin>>x>>y>>z;
if(x==0) continue; // 特判
flag=1;
y=z-y;
a=a*y%MOD; // 注意取模
b=b*z%MOD;
}
exgcd(b, MOD);
x = (x % MOD + MOD) % MOD;
printf("%lld", (c+a * (long long)(x) )% MOD);
return 0;
}
K题 Yet Another Problem About Pi 关于圆周率的另一个问题
题目大意
在间距为
w
w
w ,
d
d
d 的网格上走
π
π
π 的距离,求最多经过几个网格区域。
考察内容
贪心,枚举,数学知识
分析
贪心,只走直线短边或对角线。直线短边每走一段,新经过区域为 2。对角线每走一段,新经过区域为 3 。
设一共走了
x
x
x 条直线,
y
y
y 条对角线,直线短边长
m
i
n
1
=
m
i
n
(
w
,
d
)
min1=min(w,d)
min1=min(w,d) ,对角线长
d
1
=
w
2
+
d
2
d1=\sqrt{w^2+d^2}
d1=w2+d2 ,经过网格区域数
f
(
x
,
y
)
f(x,y)
f(x,y) ,则有
{ x ∗ m i n 1 + y ∗ d 1 ≤ π f ( x , y ) = 2 x + 4 + 3 y \left\{ \begin{aligned} x*min1+y*d1≤π \\ f(x,y)=2x+4+3y \end{aligned} \right. {x∗min1+y∗d1≤πf(x,y)=2x+4+3y
求解
m
a
x
(
f
(
x
,
y
)
)
max(f(x,y))
max(f(x,y))
f
(
x
,
y
)
f(x,y)
f(x,y) 代入
y
=
π
−
x
∗
m
i
n
1
d
1
y=\frac{π-x*min1}{d1}
y=d1π−x∗min1 后变为
f
(
x
)
f(x)
f(x) ,求导,发现导数
f
′
(
x
)
=
2
−
3
m
i
n
1
d
1
f'(x) = 2-3\frac{min1}{d1}
f′(x)=2−3d1min1 ,为常数,只能在
x
=
0
x=0
x=0 或
x
x
x 最大的合法取值处取到
f
(
x
)
f(x)
f(x) 最大值。
考虑到 x , y x,y x,y 为非负整数,不妨在两端枚举 x , y x,y x,y 的取值,取合法的最大值。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e6+10;
ll n,m,a[N];
double pi=3.141592653589793238462643383;
double min1,d1;
ll f(ll x){
ll y=(pi-x*min1)/d1;
return 2*x+4+3*y;
}
bool ck(ll x,ll y){
if(x*min1+y*d1<=pi)return 1; //
else return 0;
}
int main(){
ios::sync_with_stdio(0); cin.tie(0);
int t; cin>>t;
while(t--){
ll ans=0;
double w,d;
cin>>w>>d;
min1=min(w,d);
d1=sqrt(w*w+d*d);
ll x=(pi+min1+0.0000000001)/min1;
ll num=2000; //
for(int i=0;i<=min(num,x);i++){ // 0到num
if(ck(i,(ll)(pi-x*min1)/d1))
{
ans=max(ans,f(i));
}
}
for(int i=max((ll)0,x-num);i<=x;i++){ // x-num 到 x
if(ck(i,(ll)(pi-x*min1)/d1))
{
ans=max(ans,f(i));
}
}
x=(pi+min1+0.0000000001)/min1; // 全直
ans=max(ans,2*x+2);
x=(pi+d1+0.0000000001)/d1; // 全斜
ans=max(ans,3*x+1);
cout<<ans<<endl;
}
return 0;
}
/*
3
0.91 0.91
0.01 0.01
0.0001 0.0001
11
670
66647
*/
进阶题
D题 OR 或运算
题目大意
给出相邻两位
𝑎
𝑖
−
1
or
𝑎
𝑖
𝑎_{𝑖−1} \operatorname{or} 𝑎_𝑖
ai−1orai、
𝑎
𝑖
−
1
+
𝑎
𝑖
𝑎_{𝑖−1} + 𝑎_𝑖
ai−1+ai 的结果,询问有多少个
a
i
a_i
ai 序列满足要求
考察内容
位运算
分析
因为
𝑎
𝑖
−
1
+
𝑎
𝑖
=
𝑎
𝑖
−
1
or
𝑎
𝑖
+
𝑎
𝑖
−
1
and
𝑎
𝑖
𝑎_{𝑖−1}+𝑎_𝑖=𝑎_{𝑖−1} \operatorname{or} 𝑎_𝑖 + 𝑎_{𝑖−1} \operatorname{and} 𝑎_𝑖
ai−1+ai=ai−1orai+ai−1andai ,可以求出相邻两位按位与的结果。
又因为
a
[
1
]
a[1]
a[1] 确定就能确定整个序列,所以只需枚举
a
[
1
]
a[1]
a[1] 的每个二进制位。
对于 a [ 1 ] a[1] a[1] 的每个二进制位,扫一遍按位或和按位与数组的相应位置,来判断01能不能放。
- 如果01都可以放,结果就*2
- 如果01只能放一个,结果不变
- 如果01都不能放,结果变成0
复杂度 31 ∗ O ( n ) 31*O(n) 31∗O(n) ,其中 31 是 a [ 1 ] a[1] a[1] 的位数
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MN = 100005;
int N, B[MN], C[MN];
void Solve() {
scanf("%d", &N);
for (int i = 1; i <= N - 1; ++i) scanf("%d", &B[i]); // or(按位或)后的值
for (int i = 1; i <= N - 1; ++i) scanf("%d", &C[i]), C[i] -= B[i]; // 记录C[i]-B[i]即 and(按位与)后的值
int ans = 1;
for (int j = 0; j < 31; ++j) { // 枚举a[1]的每一位
int a0 = 1, a1 = 1;
for (int i = 1; i <= N - 1; ++i) {
int vo = B[i] >> j & 1; // 取出B[i]第j位
int va = C[i] >> j & 1; // 取出C[i]第j位
int b0 = 0, b1 = 0;
if (vo && va)
b1 = a1; // 都是1,只有1能保留
if (vo && !va)
b1 = a0, b0 = a1; // 01都有,都能保留
if (!vo && !va)
b0 = a0; // 都是0,只有0能保留
a0 = b0, a1 = b1; //
}
ans *= a0 + a1; // 更新答案
}
printf("%d\n", ans);
}
int main() { // AC代码
Solve();
}