唯一一个在扩展题库上做对这几题中的每一题的人,此刻你正在看他的文章。
14027:[HEOI2015]兔子与樱花
时间限制: 1000 ms 内存限制: 262144 KB
提交数: 109 通过数: 1
【题目描述】
很久很久之前,森林里住着一群兔子。有一天,兔子们突然决定要去看樱花。兔子们所在森林里的樱花树很特殊。樱花树由n个树枝分叉点组成,编号从0到n-1,这n个分叉点由n-1个树枝连接,我们可以把它看成一个有根树结构,其中0号节点是根节点。这个树的每个节点上都会有一些樱花,其中第i个节点有c_i朵樱花。樱花树的每一个节点都有最大的载重m,对于每一个节点i,它的儿子节点的个数和i节点上樱花个数之和不能超过m,即son(i) + c_i <= m,其中son(i)表示i的儿子的个数,如果i为叶子节点,则son(i) = 0
现在兔子们觉得樱花树上节点太多,希望去掉一些节点。当一个节点被去掉之后,这个节点上的樱花和它的儿子节点都被连到删掉节点的父节点上。如果父节点也被删除,那么就会继续向上连接,直到第一个没有被删除的节点为止。
现在兔子们希望计算在不违背最大载重的情况下,最多能删除多少节点。
注意根节点不能被删除,被删除的节点不被计入载重。
【输入】
第一行输入两个正整数,n和m分别表示节点个数和最大载重
第二行n个整数c_i,表示第i个节点上的樱花个数
接下来n行,每行第一个数k_i表示这个节点的儿子个数,接下来k_i个整数表示这个节点儿子的编号
【输出】
一行一个整数,表示最多能删除多少节点。
【输入样例】
10 4
0 2 2 2 4 1 0 4 1 1
3 6 2 3
1 9
1 8
1 1
0
0
2 7 4
0
1 5
0
【输出样例】
4
【提示】
对于100%的数据,1 <= n <= 2000000, 1 <= m <= 100000, 0 <= c_i <= 1000
数据保证初始时,每个节点樱花数与儿子节点个数之和大于0且不超过m
【来源】
没有写明来源
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#define maxn 2000005
using namespace std;
char ch;
int n,k,b,cnt,sum[maxn],tot,now[maxn],son[maxn],pre[maxn],f[maxn],g[maxn],list[maxn];
bool ok;
void read(int &x){
for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1;
for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
if (ok) x=-x;
}
void put(int a,int b){pre[++tot]=now[a],now[a]=tot,son[tot]=b;}
void dfs(int u){
int st=cnt;
for (int p=now[u],v=son[p];p;p=pre[p],v=son[p]) dfs(v),f[u]+=f[v],list[++cnt]=g[v]-1;
sort(list+st+1,list+cnt+1);
for (int i=st+1;i<=cnt&&g[u]+list[i]<=k;i++) g[u]+=list[i],f[u]++;
cnt=st;
}
int main(){
read(n),read(k);
for (int i=0;i<n;i++) read(g[i]);
for (int i=0;i<n;i++){
read(sum[i]);
for (int j=1;j<=sum[i];j++) read(b),put(i,b);
}
for (int i=0;i<n;i++) g[i]+=sum[i];
dfs(0);
printf("%d\n",f[0]);
return 0;
}
14028:[HEOI2015]公约数数列
时间限制: 1000 ms 内存限制: 262144 KB
提交数: 13 通过数: 1
【题目描述】
设计一个数据结构. 给定一个正整数数列 a0,a1,...,an−1
,你需要支持以下两种操作:
1. MODIFY id x: 将 aid
修改为 x
.
2. QUERY x: 求最小的整数 p(0<=p<n)
,使得 gcd(a0,a1,...,ap)∗XOR(a0,a1,...,ap)=x
. 其中 XOR(a0,a1,...,ap)
代表 a0,a1,...,ap
的异或和,gcd
表示最大公约数。
【输入】
输入数据的第一行包含一个正整数 n
.
接下来一行包含 n
个正整数 a0,a1,...,an−1
.
之后一行包含一个正整数 q
,表示询问的个数。
之后 q 行,每行包含一个询问。格式如题目中所述。
【输出】
对于每个 QUERY 询问,在单独的一行中输出结果。如果不存在这样的 p,输出 no.
【输入样例】
10
1353600 5821200 10752000 1670400 3729600 6844320 12544000 117600 59400 640
10
MODIFY 7 20321280
QUERY 162343680
QUERY 1832232960000
MODIFY 0 92160
QUERY 1234567
QUERY 3989856000
QUERY 833018560
MODIFY 3 8600
MODIFY 5 5306112
QUERY 148900352
【输出样例】
6
0
no
2
8
8
【提示】
对于 100% 的数据,n≤100000,q≤10000,ai≤109(0≤i<n)
,QUERY x
中的 x≤1018
,MODIFY id x 中的 0≤id<n,1≤x≤109
.
【来源】
没有写明来源
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int MAXN = 1e5+10;
int N, M;
int bl[1001], br[1001], pos[MAXN], block, num;
int Gcd[MAXN], Xor[MAXN];
int a[MAXN];
set<int>S[1001];
int gcd(int a, int b) {return b==0?a:gcd(b, a%b);}
void build(int t)
{
S[t].clear();
Gcd[bl[t]] = a[bl[t]]; Xor[bl[t]] = a[bl[t]];
S[t].insert(Xor[bl[t]]);
for(int i = bl[t]+1; i <= br[t]; i++){
Gcd[i] = gcd(Gcd[i-1], a[i]);
Xor[i] = Xor[i-1]^a[i];
S[t].insert(Xor[i]);
}
}
int main()
{
int id, val;
scanf("%d", &N);
for(int i = 1; i <= N; i++){
scanf("%d", &a[i]);
}
block = (int)sqrt(N);
for(int i = 1; i <= N; i+=block){
bl[++num] = i; br[num] = min(N,i+block-1);
for(int j = bl[num]; j <= br[num]; j++)
pos[j] = num;
}
for(int i = 1; i <= num; i++) build(i);
char com[10];
scanf("%d", &M);
while(M--){
scanf("%s", com);
if(com[0] == 'M'){
scanf("%d %d", &id, &val);
a[++id] = val;
build(pos[id]);
}
else{
LL xx = 0;
int Lxor = 0, Lgcd = 0;
scanf("%lld", &xx);
int flag = 0;
for(int i = 1; i <= num; i++){
int T = gcd(Lgcd, Gcd[br[i]]);
if(T != Lgcd){
for(int j = bl[i]; j <= br[i]; j++)
if((LL)gcd(Lgcd, Gcd[j])*(LL)(Xor[j]^Lxor) == xx){
flag = j;
break;
}
if(flag) break;
}
else{
if(xx%T == 0 && S[i].count((int)(xx/T)^Lxor)){
for(int j = bl[i]; j <= br[i]; j++){
if((LL)gcd(Lgcd, Gcd[j])*(LL)(Xor[j]^Lxor) == xx){
flag = j;
break;
}
}
}
if(flag) break;
}
Lgcd = T; Lxor^=Xor[br[i]];
}
if(flag == 0) puts("no");
else printf("%d\n", flag-1);
}
}
return 0;
}
14029:[HEOI2015]定价
时间限制: 1000 ms 内存限制: 262144 KB
提交数: 22 通过数: 1
【题目描述】
在市场上有很多商品的定价类似于 999 元、4999 元、8999 元这样。它们和 1000 元、5000 元和 9000 元并没有什么本质区别,但是在心理学上会让人感觉便宜很多,因此也是商家常用的价格策略。不过在你看来,这种价格十分荒谬。于是你如此计算一个价格 p(p 为正整数)的荒谬程度:
1、首先将 p 看做一个由数字组成的字符串(不带前导 0);
2、然后,如果 p 的最后一个字符是 0,就去掉它。重复这一过程,直到 p 的最后一个字符不是 0;
3、记 p 的长度为 a,如果此时 p 的最后一位是 5,则荒谬程度为 2 * a - 1;否则为 2 * a。
例如,850 的荒谬程度为 3,而 880 则为 4,9999 的荒谬程度为 8。
现在,你要出售一样闲置物品,你能接受的定价在 [L, R] 范围内,你想要给出一个荒谬度最低的价格。
【输入】
输入文件的第一行包含一个正整数 T,表示测试数据的数目。
每个测试数据占单独的一行,包含两个空格分隔的正整数 L, R,表示定价的区间。
【输出】
对于每个测试数据,在单独的一行内输出结果。如果荒谬度最低的价格不唯一,输出最小的那个。
【输入样例】
3
998 1002
998 2002
4000 6000
【输出样例】
1000
1000
5000
【提示】
对于 100% 的数据,T ≤ 100,1 ≤ L ≤ R ≤ 10^9.
【来源】
没有写明来源
#include <bits/stdc++.h>
using namespace std;
const int inf = 1e9+1;
struct node {
int x, y;
node(int _x=0, int _y=0):x(_x), y(_y){}
inline node operator +(const node &t)const {
if(x < t.x) return *this;
if(x > t.x) return t;
return node(x, min(y, t.y));
}
};
node f[11][11][11][2];
bool vis[11][11][11][2];
int dl[11], dr[11];
inline node dfs(int len, int s, int cnt0, bool flg, bool fl, bool fr, int tmp) {
if(!len) return node((flg ? 2*(s-cnt0)-1 : 2*(s-cnt0)), tmp);
if(!fl && !fr && vis[len][s][cnt0][flg]) return f[len][s][cnt0][flg];
node res = node(inf, inf);
int mn = fl ? dl[len] : 0, mx = fr ? dr[len] : 9;
for(int i = mn; i <= mx; ++i)
res = res + dfs(len-1, s+(s||i), i?0:cnt0+1, i ? i==5: flg, fl&&i==mn, fr&&i==mx, tmp*10+i);
if(!fl && !fr) {
vis[len][s][cnt0][flg] = 1;
f[len][s][cnt0][flg] = res;
}
return res;
}
inline int solve(int l, int r) {
memset(dl, 0, sizeof dl);
memset(dr, 0, sizeof dr);
int lenl = 0, lenr = 0;
while(l) dl[++lenl] = l % 10, l /= 10;
while(r) dr[++lenr] = r % 10, r /= 10;
node res = dfs(lenr, 0, 0, 0, 1, 1, 0);
return res.y;
}
int L, R;
int main () {
int T;
scanf("%d", &T);
while(T--) {
memset(vis, 0, sizeof vis);
scanf("%d%d", &L, &R);
printf("%d\n", solve(L, R));
}
}
14030:[HEOI2015]小L的白日梦
时间限制: 1000 ms 内存限制: 262144 KB
提交数: 3 通过数: 1
【题目描述】
在某一天,你有了一个女性朋友。
你打算利用k天时间陪她,每天有很多种娱乐方式可供选择,你需要从中选择一种进行(一天只能进行一个项目),比如说一起去看电影、一起去主题公园,一起去逛街等等,一共n种项目。当然每个项目重复太多次你都会觉得无聊,因此第i个项目最多进行c[i]次。你虽然智商很高,但是情商堪忧,即使这些你准备的活动都是希望让她开心的,不过由于你笨拙的语言表达和过于理智的行动,可能使这些活动出现意外。经过你悉心的计算,你发现如果某一天进行了第i个项目,如果一切顺利的话她应该是很高兴的,但她会有a[i]的概率不高兴。如果她本来是很高兴的,但突然今天你让她不高兴了,她就会觉得很失落,并且对你的好感度大大下降。你希望尽可能避免这种情况发生,因此你要安排这k天之内每天进行的项目,最小化她感到失落的期望次数。
你的女性朋友十分在意你,所以她的心情只会因为你发生改变。第一天之前,因为你没有邀请她进行任何活动,所以她是不高兴的。
【输入】
第一行有一个非负整数t,表示一共有t组数据。
对于每组数据,第一行有两个非负整数n,k,分别表示你准备的项目个数和你用来陪她的天数。(n<=10^5, k<=10^9)
接下来n行,每一行描述一个项目,形如“x[i]/y[i] c[i]”且三个数均为非负整数,表示进行完这个项目之后她有x[i]/y[i]的概率不高兴,并且这个项目只能进行不超过c[i]次。(x[i],y[i] <= 104,c[i] <= 10^9)
【输出】
一共t行,对于每组数据输出使她感到失落的最小期望次数,四舍五入保留6位小数。
【输入样例】
3
1 2
0/1 3
1 2
1/1 3
1 2
1/2 3
【输出样例】
0.000000
0.000000
0.250000
【提示】
【样例说明】
考虑第三组数据,因为只有一个项目所以只好每天都安排这个。
在第一天之前她总是不高兴的,一共有:
第一天不高兴,第二天也不高兴、
第一天高兴,第二天不高兴、
第一天不高兴,第二天高兴、
第一天不高兴,第二天也不高兴,
这四种情况,又因为每天的项目让她高兴或者是不高兴的概率都是0.5,因此这四种情况是等概率发生的。
只有在第二种情况下,她会感到失落一次。
因此答案是(1*1+0*3)/4=0.25.
对于100%的数据,n<=105,k<=109,数据组数不会太多,大概不超过10组,数据保证分数有意义并且∑c[i]>=k。
【来源】
没有写明来源
#include <bits/stdc++.h>
using namespace std;
typedef long long lng;
typedef long double ldb;
struct data {
int cnt; ldb val;
inline data(void) {};
inline data(int a, ldb b)
: cnt(a), val(b) {};
inline void read(void) {
static int a, b;
scanf("%d/%d", &a, &b);
val = (ldb)a / b;
scanf("%d", &cnt);
}
}A[150000], B[350000];
inline bool operator < (const data &a, const data &b) {
return a.val > b.val;
}
int n, m, cas, tot;
inline ldb calc(void) {
ldb ret = 1E18, sum = 0;
lng now = 1, rem = m;
for (int i = n; i; --i)
sum += (B[i].cnt - 1) * B[i].val * (1 - B[i].val) + (1 - B[i].val) * B[i + 1].val, rem -= B[i].cnt;
for (int i = 1; i <= n; ++i ) {
rem -= B[i].cnt;
while (now <= n && rem <= 0)
sum -= (B[now].cnt - 1) * B[now].val * (1 - B[now].val) + (1 - B[now].val) * B[now + 1].val, rem += B[now++].cnt;
if (rem <= 0)break;
sum += (B[i].cnt - 1) * B[i].val * (1 - B[i].val) + (1 - B[i - 1].val) * B[i].val;
ret = min(ret, sum + (rem - 1) * B[now - 1].val * (1 - B[now - 1].val) + (1 - B[now - 1].val) * B[now].val + (1 - B[i].val) * B[now - 1].val);
}
rem = m, sum = 0;
for (int i = 1; i <= n; ++i) {
int mn = min(rem, (lng)B[i].cnt);
if(!mn)break; else rem -= mn, sum += (mn - 1) * B[i].val * (1 - B[i].val) + (1 - B[i - 1].val) * B[i].val;
}
return ret = min(ret, sum);
}
signed main(void) {
for (scanf("%d", &cas); cas--; ) {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) {
A[i].read(); if (!A[i].cnt)--i, --n;
}
sort(A + 1, A + n + 1); tot = 0;
for (int i = 1; i <= n; ++i) {
B[++tot] = data(1, A[i].val);
if (--A[i].cnt) {
if (A[i].cnt > 1)
B[++tot] = data(A[i].cnt - 1, A[i].val);
B[++tot] = data(1, A[i].val);
}
}
B[0].val = 1, B[(n = tot) + 1].val = 0;
ldb ans = calc();
for (int i = 1; i <= n; ++i)
if (i < n + 1 - i)swap(B[i], B[n + 1 - i]);
for (int i = 1; i <= n; ++i)B[i].val = 1 - B[i].val;
ans = min(ans, calc());
printf("%.6lf\n", (double)fabs(ans));
}
}
都是毒瘤,没想到我散发欧皇气息硬是一次性过了