6.10考试总结(NOIP模拟6)
前言
就这题考的不咋样果然还挺难改的。。
T1 辣鸡
前言
我做梦都没想到这题正解是模拟,打模拟赛的时候看错题面以为是\(n\times n\)的矩阵,喜提0pts。
解题思路
氢键的数量计算起来无非主要就是两种情况:
- 整个矩阵里面的
- 各个矩阵之间相邻的
整个矩阵里的比较好算:
\(\sum\limits_{i=1}^{n}(2\times q[i].x_2-q[i].x_1)\times(q[i].y_2-q[i].y_1)\)
主要是矩阵之间的比较难整,鉴于x和y相邻的情况差不多,以下只讲述x的情况,前提是两个矩形的比较近的两个横坐标相差为1。假设矩形A为当前矩形,B为正在匹配的矩形分为4种:
B的边长大于A的(A的两端都在B的\([x_1,x_2]\)区间中):产生氢键数为 \(2 \times A\) 的纵向长度,在此还可以同时处理一下A和B矩形边长相等的情况,只不过比边长相等的长度多了一两个键,不难发现,A的两个角上也可以分别连到B上。
A的边长大于B的(B的两端都在A的\([x_1,x_2]\)区间中):产生氢键的数量处理方法与上面差不多,只不过不需要判断等于的情况了。
A的下端点在B的区间内,但上端点不在(或者反之):产生氢键数量就是两个矩形交叉的部分以及边角处。
A与B的矩阵的角相邻:直接加上1就好了。
当然,我们还需要一些优化,不难发现,对于矩阵的横坐标排序后满足单调性,如果j+1无法与i匹配那么j也不能,直接break。
code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
int n,ans;
struct Ques
{
int x,y,x2,y2;
}q[N];
bool comp(Ques x,Ques y)
{
if(x.x==y.x)
return x.y<x.y;
return x.x<y.x;
}
#undef int
int main()
{
#define int register long long
#define ll long long
scanf("%lld",&n);
if(n==1)
{
int i=1;
scanf("%lld%lld%lld%lld",&q[i].x,&q[i].y,&q[i].x2,&q[i].y2);
ans+=(q[i].x2-q[i].x)*(q[i].y2-q[i].y)*2;
printf("%lld",ans);
return 0;
}
for(int i=1;i<=n;i++)
{
scanf("%lld%lld%lld%lld",&q[i].x,&q[i].y,&q[i].x2,&q[i].y2);
ans+=(q[i].x2-q[i].x)*(q[i].y2-q[i].y)*2;
}
sort(q+1,q+n+1,comp);
for(int i=1;i<n;i++)
{
for(int j=i+1;j<=n;j++)
{
if(q[j].x-q[i].x2>1)
break;
if(q[i].x-q[j].x2==1||q[j].x-q[i].x2==1)
{
if(q[i].y2<=q[j].y2&&q[i].y>=q[j].y)
{
ans+=2*(q[i].y2-q[i].y);
if(q[i].y>q[j].y)
ans++;
if(q[i].y2<q[j].y2)
ans++;
}
else if(q[j].y2<q[i].y2&&q[j].y>q[i].y)
{
ans+=2*(q[j].y2-q[j].y)+2;
}
else if(q[i].y2>=q[j].y&&q[i].y2<=q[j].y2)
{
ans+=2*(q[i].y2-q[j].y);
if(q[i].y<q[j].y)
ans++;
if(q[i].y2<q[j].y2)
ans++;
}
else if(q[i].y<=q[j].y2&&q[i].y>=q[j].y)
{
ans+=2*(q[j].y2-q[i].y);
if(q[i].y>q[j].y)
ans++;
if(q[i].y2>q[j].y2)
ans++;
}
}
if(q[i].y-q[j].y2==1||q[j].y-q[i].y2==1)
{
if(q[i].x2<=q[j].x2&&q[i].x>=q[j].x)
{
ans+=2*(q[i].x2-q[i].x);
if(q[i].x>q[j].x)
ans++;
if(q[i].x2<q[j].x2)
ans++;
}
else if(q[j].x2<q[i].x2&&q[j].x>q[i].x)
{
ans+=2*(q[j].x2-q[j].x)+2;
}
else if(q[i].x2>=q[j].x&&q[i].x2<=q[j].x2)
{
ans+=2*(q[i].x2-q[j].x);
if(q[i].x<q[j].x)
ans++;
if(q[i].x2<q[j].x2)
ans++;
}
else if(q[i].x<=q[j].x2&&q[i].x>=q[j].x)
{
ans+=2*(q[j].x2-q[i].x);
if(q[i].x>q[j].x)
ans++;
if(q[i].x2>q[j].x2)
ans++;
}
}
if((q[i].x-q[j].x2==1||q[j].x-q[i].x2==1)&&(q[i].y-q[j].y2==1||q[j].y2-q[i].y==1))
ans++;
}
}
printf("%lld",ans);
return 0;
}
T2 模板
前言
考试的时候我也不知道咋回事,看着看着就看成小球的个数了。。。喜提0pts。
解题思路
线段树合并,启发式合并(说实话,我感觉和线段树合并没啥关系),有亿点难打,当然强者都去拿平衡树左右旋了,我这。。。
建一棵权值线段树,以时间为权值,在树上分别储存颜色的种类数与个数。
因为颜色会有负数所以我们需要离散化一下。并且将颜色与时间用pair封装压入vector数组(防止MLE)。
先进行一边dfs,求出各个节点的重儿子记为son[x]。
void dfs1(int x,int fa)
{
siz[x]=v[x].size();
for(int i=head[x];i;i=nxt[i])
{
int to=ver[i];
if(to==fa)
continue;
dfs1(to,x);
siz[x]+=siz[to];
if(siz[son[x]]<siz[to])
son[x]=to;
}
}
然后再进行dfs,以dfs的顺序来更新,先遍历子树进行处理,再遍历完之后清空处重儿子子节点的树以便重复利用空间防止对于以后的计算造成影响。对于重儿子的数据我们要重复利用。
然后先将现在的节点自身加入到线段树里,然后再将所有子节点(除重儿子之外的,毕竟重儿子的数值已经在树里了)
再以s[x](小桶最大装载量)为限制进行查找询问。最后将自己儿子的所有操作压入自己的vector数组便于自己的爸爸节点处理。
void dfs2(int x,int fa)
{
for(int i=head[x];i;i=nxt[i])
{
int to=ver[i];
if(to==fa||to==son[x])
continue;
dfs2(to,x);
clear(to);
}
if(son[x])
dfs2(son[x],x);
add(x);
for(int i=head[x];i;i=nxt[i])
{
int to=ver[i];
if(to==fa||to==son[x])
continue;
add(to);
}
ans[x]=ask(1,1,m,s[x]);
if(son[x])
{
move(x,son[x]);
swap(v[x],v[son[x]]);
for(int i=head[x];i;i=nxt[i])
{
int to=ver[i];
if(to==fa)
continue;
move(to,x);
}
}
}
对于更新,laz标记下放以及查找这一类线段树基本操作在此不做过多说明,主要讲一下将节点的数值存入线段树的操作:
用一个tim数组储存每个颜色之前出现的最晚时间,然后对于以下两种情况分别进行处理:
tim[clo]为零:也就是说该颜色从未出现过,我们增加这种颜色下表为tim
有这种颜色并且最晚大于当前要增加的时间:先将最晚的那个时间种类减去,然后加上现在的种类。
最后对于以上两种特殊情况以及最普通的出现且时间早于当前时间的情况一起将数量加一。
void add(int x)
{
for(int i=0;i<v[x].size();i++)
{
int col=v[x][i].first,time=v[x][i].second;
if(!tim[col])
{
update(1,1,m,time,1,0);
tim[col]=time;
}
else if(time<tim[col])
{
update(1,1,m,tim[col],-1,0);
update(1,1,m,time,1,0);
tim[col]=time;
}
update(1,1,m,time,0,1);
}
}
讲解到此结束,主要还是考验码力QAQ,是我太菜了。。。
code
#include<bits/stdc++.h>
#define ls x<<1
#define rs x<<1|1
using namespace std;
const int N=1e6+10;
int n,m,cnt,Q,s[N],tas[N],clo[N],ans[N];
int ys[N],siz[N],son[N<<2],tre[N<<2],tim[N],laz[N<<2];
int edg_tot,head[N],ver[N<<1],nxt[N<<1];
vector<pair<int,int > > v[N];// color time
void add_edge(int x,int y)
{
ver[++edg_tot]=y;
nxt[edg_tot]=head[x];
head[x]=edg_tot;
}
void dfs1(int x,int fa)
{
siz[x]=v[x].size();
for(int i=head[x];i;i=nxt[i])
{
int to=ver[i];
if(to==fa)
continue;
dfs1(to,x);
siz[x]+=siz[to];
if(siz[son[x]]<siz[to])
son[x]=to;
}
}
void clear(int x)
{
tre[1]=siz[1]=0;
laz[1]=1;
for(int i=0;i<v[x].size();i++)
tim[v[x][i].first]=0;
}
void push_down(int x)
{
if(!laz[x])
return ;
tre[ls]=tre[rs]=siz[ls]=siz[rs]=laz[x]=0;
laz[ls]=laz[rs]=1;
}
void push_up(int x)
{
tre[x]=tre[ls]+tre[rs];
siz[x]=siz[ls]+siz[rs];
}
void update(int x,int l,int r,int pos,int val,int size)
{
siz[x]+=size;
tre[x]+=val;
if(l==r)
return ;
push_down(x);
int mid=(l+r)>>1;
if(pos<=mid)
update(ls,l,mid,pos,val,size);
else
update(rs,mid+1,r,pos,val,size);
push_up(x);
}
void add(int x)
{
for(int i=0;i<v[x].size();i++)
{
int col=v[x][i].first,time=v[x][i].second;
if(!tim[col])
{
update(1,1,m,time,1,0);
tim[col]=time;
}
else if(time<tim[col])
{
update(1,1,m,tim[col],-1,0);
update(1,1,m,time,1,0);
tim[col]=time;
}
update(1,1,m,time,0,1);
}
}
void move(int x,int y)
{
for(int i=0;i<v[x].size();i++)
v[y].push_back(v[x][i]);
v[x].clear();
}
int ask(int x,int l,int r,int rank)
{
if(rank<=0)
return 0;
if(l==r)
return tre[x];
push_down(x);
int mid=(l+r)>>1;
if(rank>=siz[ls])
return tre[ls]+ask(rs,mid+1,r,rank-siz[ls]);
return ask(ls,l,mid,rank);
}
void dfs2(int x,int fa)
{
for(int i=head[x];i;i=nxt[i])
{
int to=ver[i];
if(to==fa||to==son[x])
continue;
dfs2(to,x);
clear(to);
}
if(son[x])
dfs2(son[x],x);
add(x);
for(int i=head[x];i;i=nxt[i])
{
int to=ver[i];
if(to==fa||to==son[x])
continue;
add(to);
}
ans[x]=ask(1,1,m,s[x]);
if(son[x])
{
move(x,son[x]);
swap(v[x],v[son[x]]);
for(int i=head[x];i;i=nxt[i])
{
int to=ver[i];
if(to==fa)
continue;
move(to,x);
}
}
}
int main()
{
scanf("%d",&n);
for(int i=1,x,y;i<n;i++)
{
scanf("%d%d",&x,&y);
add_edge(x,y);
add_edge(y,x);
}
for(int i=1;i<=n;i++)
scanf("%d",&s[i]);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&tas[i],&clo[i]);
ys[i]=clo[i];
}
sort(ys+1,ys+m+1);
cnt=unique(ys+1,ys+m+1)-ys-1;
for(int i=1;i<=m;i++)
clo[i]=lower_bound(ys+1,ys+cnt+1,clo[i])-ys;
for(int i=1;i<=m;i++)
v[tas[i]].push_back(make_pair(clo[i],i));
dfs1(1,0);
memset(siz,0,sizeof(siz));
dfs2(1,0);
scanf("%d",&Q);
for(int i=1,x;i<=Q;i++)
{
scanf("%d",&x);
printf("%d\n",ans[x]);
}
return 0;
}
T3 大佬
解题思路
首先这是一道和期望没关系的期望题,正解比较麻烦 (反正我看不懂),这里说一种比较通俗易懂的方法:
我们先考虑k天之中的情况,对于k天总方案数显然是\(m^k\)对于不同的难度不难得出以下的式子:
\(\sum\limits_{i=1}^{m}(i^k-(i-1)^k) \times wt_i\)
最难的是i的方案有\(i^k\)种,但是其中有\((i-1)^k\)种情况是不做贡献的,因为有\((i-1)^k\)种情况选不到i,以i=2,k=2为例
情况有\((1,2)(2,2)(1,1)(2,1)\)但是有\((1,1)\)这一种情况是不做贡献的,因此上式正确。
最后我们再给运算结果乘天数就好了。
code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=510,mod=1000000007;
int n,m,k,ans,base,day,s[N];
int ksm(int x,int y)
{
int sum=1;
while(y)
{
if(y&1)
sum=sum*x%mod;
y>>=1;
x=x*x%mod;
}
return sum;
}
#undef int
int main()
{
#define int register long long
#define ll long long
scanf("%lld%lld%lld",&n,&m,&k);
if(k>n)
{
printf("0");
return 0;
}
day=n-k+1;
for(int i=1;i<=m;i++)
scanf("%lld",&s[i]);
base=ksm(ksm(m,k),mod-2);
for(int i=1;i<=m;i++)
{
int temp1=ksm(i,k),temp2=ksm(i-1,k);
ans=(ans+(temp1-temp2+mod)%mod*s[i]%mod+mod)%mod;
}
printf("%lld",ans*day%mod*base%mod);
return 0;
}
T4 宝藏
解题思路
首先正解是状压,但是状压+DFS好像也能过而且及其容易理解。
首先要确定的一点是我们要DFS的状态而并非节点,设当前深度为dis[i],f[i]为i状态最小花费,len[i][j]表示i与j之间道路的距离。不难得出以下式子:
\(f[s|(1<<j-1)]=f[s]+len[i][j] \times dis[j]\)
前提是\(!(s\&(1<<j-1))\)并且\(s\&(1<<i-1)\)因为如果j进去过了就没有必要再进一遍,而从i向j打通道就一定要满足i已经被打通。
因为一开始是随机选,因此我们暴力枚举没一个节点作为一开始的节点并向下进行深搜
当然上面的这一种打法是有问题的,因为遍历的深度不同导致了后效性无法处理的问题,我们可以在f数组上面加上两维,令 \(f[x][s][dep]\)表示状态为s并且节点x深度为dep的最小花费。实现过程也与上面的大同小异。
但是我 (懒得) 不屑于码了,就给出最一开始打法的代码吧。。。
code
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=15,M=1e3,base=0x3f3f3f3f;
int n,m,ans=1e9+7,dis[M],len[M+5][M+5],f[1<<N];
void dfs(int s)
{
// cout<<s<<endl;
for(int i=1;i<=n;i++)
if((1<<(i-1))&s)
for(int j=1;j<=n;j++)
if(!((1<<(j-1))&s)&&len[i][j]!=0x3f3f3f3f)
// cout<<i<<' '<<j<<endl;
if(f[(1<<(j-1))|s]>f[s]+len[i][j]*dis[i])
{
int old=dis[j];
dis[j]=dis[i]+1;
f[(1<<(j-1))|s]=f[s]+len[i][j]*dis[i];
dfs((1<<(j-1))|s);
dis[j]=old;
}
}
//#undef int
int main()
{
// #define int register long long
// #define ll long long
scanf("%d%d",&n,&m);
memset(len,0x3f,sizeof(len));
// cout<<len[0][0]<<endl;
for(int i=1,x,y,val;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&val);
len[x][y]=len[y][x]=min(len[x][y],val);
}
/*for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
len[i][j]=min(len[i][j],len[i][k]+len[k][j]);*/
for(int i=1;i<=n;i++)
{
memset(dis,0x3f,sizeof(dis));
memset(f,0x3f,sizeof(f));
dis[i]=1;
f[1<<(i-1)]=0;
dfs(1<<(i-1));
ans=min(ans,f[(1<<n)-1]);
}
printf("%d",ans);
return 0;
}
6.10考试总结(NOIP模拟6)的更多相关文章
- 2021.10.10考试总结[NOIP模拟73]
T1 小L的疑惑 对于\(P_i\),如果所有比\(P_i\)小的数加起来也达不到\(P_i-1\),那么值域肯定不连续.否则设原来值域最大值为\(mx\),则\(P_i\)会让值域最大值增致\(mx ...
- 6.17考试总结(NOIP模拟8)[星际旅行·砍树·超级树·求和]
6.17考试总结(NOIP模拟8) 背景 考得不咋样,有一个非常遗憾的地方:最后一题少取膜了,\(100pts->40pts\),改了这么多年的错还是头一回看见以下的情景... T1星际旅行 前 ...
- 5.23考试总结(NOIP模拟2)
5.23考试总结(NOIP模拟2) 洛谷题单 看第一题第一眼,不好打呀;看第一题样例又一眼,诶,我直接一手小阶乘走人 然后就急忙去干T2T3了 后来考完一看,只有\(T1\)骗到了\(15pts\)[ ...
- 5.22考试总结(NOIP模拟1)
5.22考试总结(NOIP模拟1) 改题记录 T1 序列 题解 暴力思路很好想,分数也很好想\(QAQ\) (反正我只拿了5pts) 正解的话: 先用欧拉筛把1-n的素数筛出来 void get_Pr ...
- [考试总结]noip模拟23
因为考试过多,所以学校的博客就暂时咕掉了,放到家里来写 不过话说,vscode的markdown编辑器还是真的很好用 先把 \(noip\) 模拟 \(23\) 的总结写了吧.. 俗话说:" ...
- 2021.9.17考试总结[NOIP模拟55]
有的考试表面上自称NOIP模拟,背地里却是绍兴一中NOI模拟 吓得我直接文件打错 T1 Skip 设状态$f_i$为最后一次选$i$在$i$时的最优解.有$f_i=max_{j<i}[f_j+a ...
- [考试总结]noip模拟10
不小心有咕掉了一段时间 这次考试咕掉的分数也是太多了 然后就是这次暴力完全没有打满 遗憾啊遗憾 T1 入阵曲 前面的题目背景故意引导我们去往矩阵快速幂的方向去想 然而半毛钱关系没有 其实就是维护前缀和 ...
- 2021.10.15考试总结[NOIP模拟77]
\(n=40\)考虑\(meet \;in \;the \;middle\) 某个元素有关的量只有一个时考虑转化为树上问题 对暴力有自信,相信数据有梯度 没了 UPD:写了个略说人话的. T1 最大或 ...
- 2021.10.18考试总结[NOIP模拟76]
T1 洛希极限 不难发现每个点肯定是被它上一行或上一列的点转移.可以预处理出每个点上一行,上一列最远的能转移到它的点,然后单调队列优化. 预处理稍显ex.可以用并查集维护一个链表,记录当前点之后第一个 ...
随机推荐
- 电脑提示无法装入/加载SolidWorks DLL文件:sldshellutils如何解决
电脑提示无法装入/加载SolidWorks DLL文件:sldshellutils如何解决 参考资料:http://www.xitongcheng.com/jiaocheng/dnrj_article ...
- Codeforces Round #704 (Div. 2)
A. Three swimmers 题意:第一个人跳水是每隔a分钟去一次,第二个人跳水是每隔b分钟,第三个人跳水是每隔c分钟,一个人准备在p分钟的 时候去跳水,问需要最少等待多长时间才能轮到前三个人 ...
- Codeforces Round #697 (Div. 3)
A.Odd Divisor 题意:问一个数是不是含有奇数因子 思路:就直接给这个数循环除以2,看看最后剩下的数是不是0,如果不是就有奇数因子,如果是就没有 想不到:1)当时想着用log2来解决问题,后 ...
- mysql知识点归纳-执行计划篇
愿历尽千帆,归来仍是少年 缘由: 优化sql,顾此记录一下,以便温习之用. 前置: sql执行过程:客户端 -> 连接器 -> 分析器 (或查询缓存 - > end) -> 优 ...
- vscode 取消 eslint everywhere
vscode装了eslint插件,一不小心点了eslint everywhere 然后任务栏就变成这样了 eslint前面是双钩 不管你打开什么项目,什么工作空间,永远都是默认开启ESlint!!! ...
- 25.Qt Quick QML-500行代码实现"合成大西瓜游戏"
"合成大西瓜"这个游戏在年前很火热,还上过微博热搜,最近便玩了一阵还挺有意思的,所以研究了一下小球碰撞原理,自己亲自手写碰撞算法来实现一个合成大西瓜游戏.并支持任意大小布局,你想玩 ...
- [bug] springboot 静态资源 layui.css 404
目录结构 引用路径 <link rel="stylesheet" href="../static/layui/css/layui.css" type=&q ...
- [DB] MapReduce
概述 大数据计算的核心思想:移动计算比移动数据更划算 MapReduce既是一个编程模型,又是一个计算框架 包含Map和Reduce两个过程 终极目标:用SQL语句分析大数据(Hive.SparkSQ ...
- Linux 内存 占用较高问题排查
Linux 内存 占用较高问题排查 niuhao307523005 2019-04-24 14:31:55 11087 收藏 11展开一 查看内存情况#按 k 查看 free #按兆M查看 free ...
- Zabbix5.0服务端部署
Zabbix5.0服务端部署 基础环境配置 [root@localhost ~]# systemctl disable --now firewalld Removed symlink /etc/sys ...