一场三星gym
A
题意
一个类似与约瑟夫环的问题,一共有 N N N 个人,可以从中选出前 Y Y Y 个人,这 Y Y Y 个人会按照隔一人淘汰一人的方式,淘汰至只剩一个人(成环淘汰,或者循环数组淘汰),已知,我们选择前 [ L , N ] [L, N] [L,N] 个人出来的概率是相等的,问编号为 X X X 的人存活下来的概率,用最简分数来表示。
思路
第一次打表找规律做题,原因可能是吉林自闭的太厉害了,于是就回来之后有了心理暗示= =
人数 | 二进制 | 存活编号 | 二进制 |
---|---|---|---|
1 | 1 | 1 | 1 |
2 | 10 | 1 | 1 |
3 | 11 | 3 | 11 |
4 | 100 | 1 | 1 |
5 | 101 | 3 | 11 |
6 | 110 | 5 | 101 |
7 | 111 | 7 | 111 |
8 | 1000 | 1 | 1 |
打表之后先是发现
2
n
2^n
2n 的人数存活下来的都是
1
1
1,然后发现左侧到右侧就是,人数的二进制去掉最高位的
1
1
1,左移一位后再加
1
1
1。那么右侧到左侧就是右移一位后,在所有可能的高位上加
1
1
1。
那么就是处理当前位置
X
X
X 枚举可能的高位,判断是否在区间
[
L
,
N
]
[L, N]
[L,N] 中,然后计数取最简分数即可
代码
int main()
{
int T;
sd(T);
rep(cas, 1, T+1){
ll x, n, l;
ll cnt1 = 0, cnt2;
scanf("%I64d %I64d %I64d", &x, &l, &n);
cnt2 = n - l + 1;
cnt1 = max(0LL, x-l);
ll num = x>>1;
int len = 0;
if(x&1){
while((1LL<<len) <= num) len++;
while(((1LL<<len) + num) <= n){
if(((1LL<<len) + num) >= l) cnt1++;
len++;
}
}
ll div = gcd(cnt1, cnt2);
cnt1 /= div;
cnt2 /= div;
printf("Case %d: %I64d/%I64d\n", cas, cnt1, cnt2);
}
return 0;
}
C
题意
用来签到的水题,给出 n n n 个数,判断和是不是 k k k,判断存不存在连续两个数字差为 1 1 1
代码
int a[maxn];
int main()
{
int T;
sd(T);
rep(cas, 1, T+1){
int sum, n;
int num = 0, can = 0;
sdd(sum, n);
rep(i, 0, n){
sd(a[i]);
if(i && a[i]-a[i-1]==1) can = 1;
num += a[i];
}
printf("Case %d: Thank You BACS!!! ", cas);
if(sum == num) printf("Thik ache. ");
else printf("Bojjat dokandar!! ");
if(can) printf("Yes\n");
else printf("No\n");
}
return 0;
}
L
题意
给出 n n n 个人到达和离开的时间,问想要见到至少 k k k 个人,则至少需要呆多长时间,需要注意的是,样例二中给出第 6 6 6 秒同时有人来和走,但是第 6 6 6 秒可以同时见到这两个人,那么停留的时间就是0
思路
把所有的时间排序,把每个时间标记上是来的还是走的,然后用尺取法维护见到 k k k 个人的最小时间,需要小心左指针越过右指针的情况
代码
PII a[maxn];
int main()
{
int T, n, k;
sd(T);
rep(cas, 1, T+1){
sdd(n, k);
rep(i, 0, n){
int st, en;
sdd(st, en);
a[i<<1] = mk(st, 0);
a[i<<1|1] = mk(en, 1);
}
sort(a, a+2*n);
int st = 0, en = 0, cnt = 1;
int ans = INT_MAX;
while(st < 2*n){
while(cnt < k && en < 2*n-1){
en++;
if(a[en].se == 0) ++cnt;
}
if(cnt == k) ans = min(ans, a[en].fi - a[st].fi);
if(a[st++].se == 1) cnt--;
while(st > en){
en++;
if(a[en].se == 0) ++cnt;
}
}
printf("Case %d: %d\n", cas, ans);
}
return 0;
}