********今天得了在清北的最高分,有点开心wwwww,mjy爱您!
树
【问题背景】
zhx 是二叉查找树大师。
【问题描述】
二叉查找树是一种特殊的二叉树(每个节点最多只有两个儿子的树)。树的
每个节点上存有一个唯一的值,并且满足:这个节点的左子树内所有点的值都
比这个节点的值小,且右子树内所有点的值都比这个节点的值要大。
对于一棵二叉查找树T,我们可以将一个值为x的新点插入T中,且保持
树的性质。算法如下:
需要将x插入树T时,执行insert(x, T.root) 。
现在有N 个数需要插入一棵空树中。给定插入序列,请在每个元素被插入
之后,输出所有节点的深度总和(根的深度为0)。
【输入格式】
输入的第一行一个整数n,表示序列长度。
以下n行是序列中的数字,这些数字是各不相同的,在[1,n]区间。
【输出格式】
输出n行,第 i行整数表示第i个数插入树后,至这个节点的节点深度总和。
【样例输入】
8
3
5
1
6
8
7
2
4
【样例输出】
0
1
2
4
7
11
13
15
【数据规模与约定】
对于50%的数据,满足N ≤ 1000
对于100%的数据,满足N ≤ 3 ∗ 1e5。
解析:
大概就是一道非常裸的二叉查找树的题??
但是如果直接暴力模拟的话会过不去,这是因为如果按顺序插入所有节点的时候复杂度会很高。
假设在插入节点x的时候我们已经有了一个树体,我们找比x小的最大节点设为u,比x大的最小节点设为v;
那么可以证明u和v一定是相连的,则若要插入x则要么为u的右节点,要么为v的左节点
即下图的两种情况
假设深度为depth[i],则depth[x]=max(depth[u],depth[v])+1;
现在问题变为了如何找u和v
答案就是:将输入序列倒过来维护,每当x找到了u/v,就把x删掉
具体做法:我们可以用双向链表来解决,当把所有的u、v都维护好后再正过来求总depth
代码
#include
#define MAXN 300005
int n;
int a[MAXN];
int prev[MAXN], next[MAXN];
int u[MAXN], v[MAXN];
int deep[MAXN];
int main(void)
{
scanf("%d", & n);
for (int i = 1; i <= n; ++i)
scanf("%d", a + i);
for (int i = 1; i <= n; ++i)
{
prev[i] = i - 1;
next[i] = i + 1;
}
int x;
for (int i = n; i > 1; --i)
{
x = a[i];
u[x] = prev[x];
v[x] = next[x];
next[prev[x]] = next[x];
prev[next[x]] = prev[x];
}
long long sum = 0;
for (int i = 1; i <= n; ++i)
{
x = a[i];
if ((u[x] >= 1) && (u[x] <= n))
if (deep[x] < deep[u[x]] + 1)
deep[x] = deep[u[x]] + 1;
if ((v[x] >= 1) && (v[x] <= n))
if (deep[x] < deep[v[x]] + 1)
deep[x] = deep[v[x]] + 1;
sum += deep[a[i]];
printf("%lld\n", sum);
}
return 0;
}
赛
【问题背景】
zhx 举办了一场 OI 竞赛。
【问题描述】
n人参加信息学竞赛,共有 m道题。现在比赛已经结束,评分正在进行中,
对于已经结束评测的试题,已知每名考生这道题的答案是否正确,对于未结束评
测的试题,只知道每名考生是否ᨀ交答案。每个题分数固定,提交正确的答案的
考生可以得到这一题的分数,分数越高排名越靠前,分数相同编号小的考生排名
靠前。这 n 人中,排名最靠前的 s 人将获得入选代表队的资格,而这 s 个中将通
过最终的科学委员会面试选出其中的t个人。输入当前的评测信息(包括是否提
交,以及已经评测部分的是否正确)以及每道题的分值,问最终的 t人代表队共
有多少种组队的可能。
【输入格式】
输入文件第一行是m,接下去 m行每行一个整数来表示每道题目的分值(整
数是正的表示该题已经评测,否则表示该题尚未评测,该题目的分值为这个整数
的绝对值)。然后是一个整数 n,接下去是一个 n 行 m 列的字母阵,字母阵只包
含 YN 两种字母(Yes or No),如果第 i 题已经完成评测,那么这个字母矩阵中
第 j 行第 i 列的表示第 j 名选手的第 i 题是否已经得分;如果第 i 题尚未完成评
测,那么这个字母矩阵中第 j 行第 i 列的表示第 j 名选手的第 i 题是否提交了解
答。最后两行两个数字,分别为s 和t。
【输出格式】
输出文件只有一行,即为最终的t人代表队的组队方案数。
【样例输入】
2
1
-10
4
NY
YN
YN
YN
3
2
【样例输出】
5
【数据规模与约定】
对于100%的数据, 满足1 ≤ N,M ≤ 50
解析:
我们先维护每个人所能得到的最大最小分值
其实也只有最大最小值有用
如果我们先选s个再选t个的话,答案一定会重(我在考场上是用的Hash判重,debug两个小时到爆炸)
因此我们选择直接枚举选入的t个人
设maxs[i],mins[i]非别为i号能得到的最多最少的分
给以maxs数组为第一关键字,mins为第二关键字排序,依次选择,假设i为可以进队的t人中 maxs最小的人
若前i个人中已经进了t人, 那么实际中有一些人是一定会进的->就是mins[x]>maxs[i]的那些人
上图中,假设有p[i]人的mins[x]>maxs[i]
假设前p[i]人中有k人进队,在(p[i]~i)范围内有t-k-1人进队,(假设i一定进队)
则判断条件应有:k<=t-1(第i人必须进队)、k<=p[i](显然。)、p[i]<s-1(必须要进的t人,t<s)、p[i]-k<=s-t(p[i]-k为前p[i]中进了s没进t的人数,s-t为总的进了s没进t的人)
答案即下图(实在不会打)
代码:
//mjy的标程
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
卡
【问题背景】
zhx 是骨灰级炉石玩家。
【问题描述】
zhx 买了36个卡包,并且把他们排列成6×6的阵型准备开包。左上角的包是
(0,0),右下角为(5,5)。为了能够开到更多的金色普通卡,zhx 会为每个包添加1−
5个玄学值,每个玄学值可以是1−30中的一个整数。但是不同的玄学值会造成
不同的欧气加成,具体如下:
1、同一个卡包如果有两个相同的玄学值会有无限大的欧气加成。
2、同一个卡包如果有两个相邻的玄学值会有A点欧气加成。
3、相邻的两个卡包如果有相同的玄学值会有B点欧气加成。
4、相邻的两个卡包如果有相邻的玄学值会有C点欧气加成。
5、距离为2的卡包如果有相同的玄学值会有D点欧气加成。
6、距离为2的卡包如果有相邻的玄学值会有E点欧气加成。
以上的所有加成是每存在一个符合条件的就会加一次,如一包卡有1,2,3的玄
学值就会加两次。
但是,玄学值是个不可控的东西,即使是 zhx 也只能自己决定
2,2 , 2,3 , 3,2 , (3,3)这几包卡的玄学值。为了能够抽到更多的金色普通卡,zhx
想知道自己能够获得的最少的欧气加成是多少。注意你只能修改玄学值,不能修
改玄学值的个数。
【输入格式】
输入的第一行有5个整数A,B,C,D,E。
接下去有6×6的代表初始的玄学值。
每个玄学值为[n:a1,a2,⋯,an]的᧿述形式。
【输出格式】
一行一个整数代表答案。
【样例输入】
5 4 3 2 1
[1:1][1:2][1:3][1:4][1:5][1:6]
[1:1][1:2][1:3][1:4][1:5][1:6]
[1:1][1:2][5:1,2,3,4,5][5:1,2,3,4,5][1:5][1:6]
[1:1][1:2][5:1,2,3,4,5][5:1,2,3,4,5][1:5][1:6]
[1:1][1:2][1:3][1:4][1:5][1:6]
[1:1][1:2][1:3][1:4][1:5][1:6]
【样例输出】
250
【数据规模与约定】
对于100%的数据,1 ≤ A,B,C,D,E ≤ 100,1 ≤ n≤ 5,1 ≤ ai≤ 30。有部分分。
注:距离为曼哈顿距离
解析:
一道考场上看不懂,听完题解一脸蒙蔽的题。(九维DP也是强,蒟蒻的我怕是明年也想不到)
曼哈顿距离:d=|x1-x2|+|y1-y2|;
实在是不想写QUQ反正考了我也不会写
就看看代码吧[逃]
//mjy的标程
#include
#include
#include
#include
using namespace std;
#define now pre[a][b][c][d][e][s1][s2][s3][s4]
#define dis(a,b,c,d) (abs(a-c)+abs(b-d))
const int INF=0x3f3f3f3f;
int A,B,C,D,E,num[10][10],value[10][10][10],delta[10][10][40],dp[31][6][6][6][6][2][2][2][2];
char s[500];
bool map[6][6][6][6];
int main()
{
freopen("card.in","r",stdin);
freopen("card.out","w",stdout);
scanf("%d%d%d%d%d",&A,&B,&C,&D,&E);
for (int a=0;a<6;a++)
{
scanf("%s",s);
int p=0;
for (int b=0;b<6;b++)
{
int px=p;
while (s[px]!=']')
px++;
p++;
num[a][b]=s[p]-'0';
p++;
p++;
for (int c=1;c<=num[a][b];c++)
{
int v=0;
while (s[p]>='0' && s[p]<='9')
{
v=v*10+s[p]-'0';
p++;
}
value[a][b][c]=v;
p++;
}
p=px+1;
}
}
int base=0;
for (int a=0;a<6;a++)
for (int b=0;b<6;b++)
if (a>=2 && a<=3 && b>=2 && b<=3) ;
else
{
sort(value[a][b]+1,value[a][b]+num[a][b]+1);
for (int c=2;c<=num[a][b];c++)
if (value[a][b][c]-value[a][b][c-1]==1) base+=A;
for (int c=2;c<=3;c++)
for (int d=2;d<=3;d++)
{
if (dis(a,b,c,d)==1)
{
for (int e=1;e<=num[a][b];e++)
{
delta[c][d][value[a][b][e]]+=B;
delta[c][d][value[a][b][e]-1]+=C;
delta[c][d][value[a][b][e]+1]+=C;
}
}
if (dis(a,b,c,d)==2)
{
for (int e=1;e<=num[a][b];e++)
{
delta[c][d][value[a][b][e]]+=D;
delta[c][d][value[a][b][e]-1]+=E;
delta[c][d][value[a][b][e]+1]+=E;
}
}
}
for (int c=0;c<6;c++)
for (int d=0;d<6;d++)
if (dis(a,b,c,d)<=2 && (c!=a || d!=b) && !map[a][b][c][d])
{
map[a][b][c][d]=map[c][d][a][b]=true;
if (c>=2 && c<=3 && d>=2 && d<=3) ;
else
{
int dist=dis(a,b,c,d);
for (int e=1;e<=num[a][b];e++)
for (int f=1;f<=num[c][d];f++)
{
if (abs(value[a][b][e]-value[c][d][f])==0)
{
if (dist==1) base+=B;
else base+=D;
}
if (abs(value[a][b][e]-value[c][d][f])==1)
{
if (dist==1) base+=C;
else base+=E;
}
}
}
}
}
memset(dp,0x3f,sizeof(dp));
dp[0][0][0][0][0][0][0][0][0]=base;
for (int a=0;a<30;a++)
for (int b=0;b<=num[2][2];b++)
for (int c=0;c<=num[2][3];c++)
for (int d=0;d<=num[3][2];d++)
for (int e=0;e<=num[3][3];e++)
for (int s1=0;s1<=1;s1++)
for (int s2=0;s2<=1;s2++)
for (int s3=0;s3<=1;s3++)
for (int s4=0;s4<=1;s4++)
if (dp[a][b][c][d][e][s1][s2][s3][s4]!=INF)
{
int v=dp[a][b][c][d][e][s1][s2][s3][s4];
for (int sx1=0;sx1<=(b!=num[2][2]);sx1++)
for (int sx2=0;sx2<=(c!=num[2][3]);sx2++)
for (int sx3=0;sx3<=(d!=num[3][2]);sx3++)
for (int sx4=0;sx4<=(e!=num[3][3]);sx4++)
{
int wmt=0;
if (sx1)
{
wmt+=delta[2][2][a+1];
if (s1) wmt+=A;
if (s2) wmt+=C;
if (s3) wmt+=C;
if (s4) wmt+=E;
}
if (sx2)
{
wmt+=delta[2][3][a+1];
if (s1) wmt+=C;
if (s2) wmt+=A;
if (s3) wmt+=E;
if (s4) wmt+=C;
}
if (sx3)
{
wmt+=delta[3][2][a+1];
if (s1) wmt+=C;
if (s2) wmt+=E;
if (s3) wmt+=A;
if (s4) wmt+=C;
}
if (sx4)
{
wmt+=delta[3][3][a+1];
if (s1) wmt+=E;
if (s2) wmt+=C;
if (s3) wmt+=C;
if (s4) wmt+=A;
}
if (sx1 && sx2) wmt+=B;
if (sx1 && sx3) wmt+=B;
if (sx1 && sx4) wmt+=D;
if (sx2 && sx3) wmt+=D;
if (sx2 && sx4) wmt+=B;
if (sx3 && sx4) wmt+=B;
int &t=dp[a+1][b+sx1][c+sx2][d+sx3][e+sx4][sx1][sx2][sx3][sx4];
if (t>v+wmt) t=v+wmt;
}
}
int ans=INF;
for (int a=0;a<=1;a++)
for (int b=0;b<=1;b++)
for (int c=0;c<=1;c++)
for (int d=0;d<=1;d++)
ans=min(ans,dp[30][num[2][2]][num[2][3]][num[3][2]][num[3][3]][a][b][c][d]);
printf("%d\n",ans);
return 0;
}