手速场,要学wqs二分了。
A - New Year Garland
题意:给三种颜色的灯,求是否可以有一种顺序使得两盏同色灯不相邻。
题解:和上次那个0,1,2,3排序的题一样,弱化版。把其中C颜色的灯视作A颜色或B颜色均可,把AB的数量补到平衡。
void test_case() {
int a[4];
scanf("%d%d%d", &a[1], &a[2], &a[3]);
sort(a + 1, a + 1 + 3);
if(a[1] + a[2] + 1 >= a[3])
puts("Yes");
else
puts("No");
}
B - Verse For Santa
题意:给一个数字序列,从第一个元素开始,至多跳过一个元素,求不超过T的前缀和最多能取到几个元素(不含跳过那个)。
题解:暴力。枚举每个前缀和,贪心把最大的那个去掉。一开始还往dp那里想浪费了不少时间。
int a[100005];
priority_queue<pii> pq;
void test_case() {
int n;
ll s;
scanf("%d%lld", &n, &s);
for(int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
ll t = 0;
pii ans = {0, 0};
for(int i = 1; i <= n; ++i) {
t += a[i];
if(t <= s)
ans = {i, 0};
}
while(!pq.empty())
pq.pop();
t = 0;
for(int i = 1; i <= n; ++i) {
t += a[i];
pq.push({a[i], i});
if(t - pq.top().first <= s) {
if(i - 1 > ans.first)
ans = {i - 1, pq.top().second};
}
}
printf("%d
", ans.second);
}
int a[100005];
void test_case() {
int n;
ll s;
scanf("%d%lld", &n, &s);
for(int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
ll t = 0;
int maxi = 0, ansi = 0;
for(int i = 1; i <= n; ++i) {
t += a[i];
if(a[i] > a[maxi])
maxi = i;
if(t - a[maxi] <= s)
ansi = maxi;
if(t <= s)
ansi = 0;
}
printf("%d
", ansi);
}
C - Stack of Presents
题意:有一个n个不重复元素的栈,从栈顶开始分别是a1,a2,...,an,圣诞老人要取出其中的不重复的m个,按顺序是b1,b2,...,bm,取出某个元素的时候必须把其顶部的全部取出来,不过放回去的时候可以摆成想要的任意顺序。拿出来和放回去都是1花费,求最小花费。
题解:放回去的时候可以总是可以摆成b的顺序,只要b的下一个元素被拿出来过,总是存在一种顺序使得它恰好只需要1花费拿出来。标记被拿过哪些就可以了,比赛的时候用的set,后来觉得没必要。
int a[100005];
int p[100005];
int b[100005];
set<int> s;
void test_case() {
int n, m;
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
p[a[i]] = i;
}
for(int i = 1; i <= m; ++i)
scanf("%d", &b[i]);
s.clear();
ll sum = 0;
int Rmost = 0;
for(int i = 1; i <= m; ++i) {
if(p[b[i]] > Rmost) {
while(p[b[i]] > Rmost) {
++Rmost;
s.insert(a[Rmost]);
}
sum += 2 * s.size() - 1;
s.erase(b[i]);
} else {
sum += 1;
s.erase(b[i]);
}
}
printf("%lld
", sum);
}
int a[100005];
int p[100005];
int b[100005];
void test_case() {
int n, m;
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
p[a[i]] = i;
}
for(int i = 1; i <= m; ++i)
scanf("%d", &b[i]);
ll sum = 0;
int Rmost = 0;
for(int i = 1; i <= m; ++i) {
if(p[b[i]] > Rmost) {
while(p[b[i]] > Rmost)
++Rmost;
sum += 2 * (Rmost - (i - 1)) - 1;
} else
sum += 1;
}
printf("%lld
", sum);
}
D - Santa's Bot
题意:有n个孩子,每个孩子有一个想要的礼物的列表,每个孩子中想要的礼物都不重复。圣诞机器人每次等概率选一个孩子x,然后等概率选择这个孩子的想要的礼物列表中的一个礼物y,然后等概率选择一个孩子z,送出去。当孩子z也想要礼物y则称为成功,否则失败。求成功的期望。
题解:首先可以求出每个礼物被抽到的概率。然后求出每个礼物送出去之后成功的概率。
[egin{align}
EX(送礼物成功) &=sumlimits_{i=1}^n P(抽到第i个礼物)EX(送第i个礼物成功) \
&=sumlimits_{i=1}^n P(抽到第i个礼物)P(送第i个礼物成功)
end{align}
]
这两个都很好求。
const int MAXN = 1e6;
ll pitem[MAXN + 5];
int citem[MAXN + 5];
void test_case() {
int n;
scanf("%d", &n);
ll invn = qpow(n, MOD - 2);
for(int i = 1; i <= n; ++i) {
int t;
scanf("%d", &t);
ll invt = qpow(t, MOD - 2);
ll p = invn * invt % MOD;
for(int j = 1; j <= t; ++j) {
int x;
scanf("%d", &x);
++citem[x];
pitem[x] += p;
}
}
ll sum = 0;
for(int i = 1; i <= MAXN; ++i) {
pitem[i] %= MOD;
sum += pitem[i] * citem[i] % MOD;
}
sum = sum % MOD * invn % MOD;
printf("%lld
", sum);
}