7.17考试总结(NOIP模拟18)[导弹袭击·炼金术士的疑惑·老司机的狂欢]
问灵十三载,等一不归人。
前言
这回考试全靠 T2 了,别的基本上没分(菜)
总感觉最近进度有亿点快,每天都在补坑,每天都在留坑。。。。
T1 导弹袭击
解题思路
因为这个题的两种长度是不一定的,因此,显然什么二分枚举都不对了。
通过细致阅读题目,我们可以得到一种 60pts 的做法:
通过 \(n^2\) 枚举任意两种导弹的较另一种时间的临界值,近而求出一个范围。
判断两个范围是否有交集就好了,大概就是下面这个柿子(假设想让 1 较于 2 更优)
\(\dfrac{L_A}{L_B}\le \dfrac{a_1\times a_2 \times (b_1-b_2)}{b_1 \times b_2\times (a_2-a_1)}(a_1>a_2)\)
\(\dfrac{L_A}{L_B}\ge \dfrac{a_1\times a_2 \times (b_1-b_2)}{b_1 \times b_2\times (a_2-a_1)}(a_1<a_2)\)
并且,我们还可以缩小一下值域,对于在相同的 a,b 不是最大的,或者相同的 b,a 不是最大的,都可以直接干掉。
正解的思路大同小异,把 \((\dfrac{1}{a_i},\dfrac{1}{b_i})\) 当作坐标系里面的一个点,用凸包维护斜率。
code
60pts
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
const int N=3e5+10,INF=1e9;
int n,cnt,a[N],b[N];
map<int,int>maxa,maxb;
bool vis[N];
struct Node
{
double a,b;
int id;
}s[N];
bool comp(Node x,Node y)
{
return x.a<y.a;
}
signed main()
{
n=read();
for(int i=1;i<=n;i++)
{
a[i]=read();
b[i]=read();
maxa[a[i]]=max(maxa[a[i]],b[i]);
maxb[b[i]]=max(maxb[b[i]],a[i]);
}
for(int i=1;i<=n;i++)
{
if(maxa[a[i]]==b[i]&&maxb[b[i]]==a[i])
s[++cnt]=(Node){a[i],b[i],i};
}
sort(s+1,s+cnt+1,comp);
for(int i=1;i<=cnt;i++)
{
bool jud=false;
double l=0,r=INF;
for(int j=1;j<i;j++)
l=max(l,s[i].a*s[j].a*(s[i].b-s[j].b)/(s[i].b*s[j].b*(s[j].a-s[i].a)));
for(int j=i+1;j<=cnt;j++)
{
if(s[i].b<s[j].b)
{
jud=true;
break;
}
r=min(r,s[i].a*s[j].a*(s[i].b-s[j].b)/(s[i].b*s[j].b*(s[j].a-s[i].a)));
}
if(l>r||l<0||r<0) jud=true;
vis[s[i].id]=jud^1;
}
for(int i=1;i<=n;i++)
if(vis[i])
cout<<i<<' ';
return 0;
}
正解
#include<bits/stdc++.h>
#define int long long
#define double long double
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
const int N=3e5+10,INF=1e9;
int n,cnt,a[N],b[N];
int top,sta[N];
double k[N];
vector<int> v[N];
bool vis[N];
struct Node
{
double a,b;
int id;
}s[N];
bool comp(Node x,Node y)
{
if(x.a!=y.a) return x.a>y.a;
return x.b>y.b;
}
double K(int i,int j)
{
return s[i].a*s[j].a*(s[j].b-s[i].b)/(s[i].b*s[j].b*(s[j].a-s[i].a));
}
signed main()
{
int rx,ry=0;
n=read();
for(int i=1;i<=n;i++)
{
s[i].a=read();
s[i].b=read();
s[i].id=i;
if(ry<s[i].b||(ry==s[i].b&&rx<s[i].a))
ry=s[i].b,rx=s[i].a;
}
sort(s+1,s+n+1,comp);
sta[++top]=1;
v[1].push_back(s[1].id);
for(int i=2;i<=n&&rx<=s[i].a;i++)
{
if(s[i].a==s[sta[top]].a)
{
if(s[i].b==s[sta[top]].b)
v[sta[top]].push_back(s[i].id);
continue;
}
v[i].push_back(s[i].id);
while(top>1&&k[sta[top]]>K(sta[top],i)) top--;
k[i]=K(sta[top],i);
sta[++top]=i;
}
for(int i=1;i<=top;i++)
for(int j=0;j<v[sta[i]].size();j++)
vis[v[sta[i]][j]]=true;
for(int i=1;i<=n;i++)
if(vis[i])
printf("%lld ",i);
return 0;
}
T2 炼金术士的疑惑
解题思路
比较水的一个题,基本上都能一眼看出是高斯消元。
无非就是把方程右边的柿子移一下项。
对于已知方程直接消元再卡一下精度就可以得到 90pts 的巨额分数。
100pts 的做法其实就是把问题方程也放进去一起消,但是不要换到上面去。
最后问题柿子的结果取个相反数就是答案了。。(真没啥好说的)
code
90pts(可能消元方法有点诡异)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=210,M=1e3+10;
int n,cnt;
double num,answer,s[N][M],ans[N],q[N],val[N];
string ch,opt;
map<string,int> ma;
inline int read()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
// cout<<i<<endl;
scanf("%lf",&num);
cin>>ch;
// cout<<ch<<endl;
if(!ma[ch]) ma[ch]=++cnt;
s[i][ma[ch]]=num;
do
{
cin>>opt;
// cout<<opt<<endl;
if(opt[0]=='=') break;
scanf("%lf",&num);
cin>>ch;
// cout<<ch<<endl;
if(!ma[ch]) ma[ch]=++cnt;
s[i][ma[ch]]=num;
}while(opt[0]!='=');
// cout<<i<<endl;
scanf("%lf",&num);
// cin>>num;
// cout<<num<<endl;
cin>>ch;
// cout<<ch<<endl;
if(!ma[ch]) ma[ch]=++cnt;
s[i][ma[ch]]=-num;
do
{
cin>>opt;
// cout<<opt<<endl;
if(opt[0]=='H') break;
scanf("%lf",&num);
cin>>ch;
// cout<<ch<<endl;
if(!ma[ch]) ma[ch]=++cnt;
s[i][ma[ch]]=-num;
}while(opt[0]!='H');
scanf("%lf",&ans[i]);
}
for(int i=1;i<=n;i++)
s[i][cnt+1]=ans[i];
scanf("%lf",&num);
cin>>ch;
if(!ma[ch]) ma[ch]=++cnt;
q[ma[ch]]=num;
do
{
cin>>opt;
if(opt[0]=='=') break;
scanf("%lf",&num);
cin>>ch;
if(!ma[ch]) ma[ch]=++cnt;
q[ma[ch]]=num;
}while(opt[0]!='=');
scanf("%lf",&num);
cin>>ch;
if(!ma[ch]) ma[ch]=++cnt;
q[ma[ch]]=-num;
do
{
cin>>opt;
if(opt[0]=='H') break;
scanf("%lf",&num);
cin>>ch;
if(!ma[ch]) ma[ch]=++cnt;
q[ma[ch]]=-num;
}while(opt[0]!='H');
}
void check()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=cnt+1;j++)
cout<<s[i][j]<<' ';
cout<<endl;
}
for(int j=1;j<=cnt;j++)
cout<<q[j]<<' ';
}
void gaosi()
{
for(int i=1;i<=n;i++)
{
int pos=0;
for(int j=1;j<=cnt;j++)
if(s[i][j])
{
pos=j;
break;
}
if(s[i][pos]!=1&&s[i][pos])
{
double temp=s[i][pos];
for(int j=pos;j<=cnt+1;j++)
s[i][j]/=temp;
}
for(int j=i+1;j<=n;j++)
{
if(!s[j][pos])
continue;
double temp=s[j][pos];
for(int k=pos;k<=cnt+1;k++)
s[j][k]-=s[i][k]*temp;
}
}
for(int i=n;i>=2;i--)
{
int pos=0;
for(int j=1;j<=cnt;j++)
if(s[i][j])
{
pos=j;
break;
}
if(s[i][pos]!=1&&s[i][pos])
{
double temp=s[i][pos];
for(int j=pos;j<=cnt+1;j++)
s[i][j]/=temp;
}
for(int j=1;j<i;j++)
{
if(!s[j][pos])
continue;
double temp=s[j][pos];
for(int k=pos;k<=cnt+1;k++)
s[j][k]-=s[i][k]*temp;
}
}
}
void solve()
{
gaosi();
for(int i=1;i<=n;i++)
for(int j=1;j<=cnt;j++)
if(s[i][j])
{
val[j]=s[i][cnt+1];
break;
}
for(int i=1;i<=cnt;i++)
answer+=q[i]*val[i];
answer*=10;
answer+=1e-6;
printf("%.1lf",answer/10.0);
}
signed main()
{
read();
solve();
return 0;
}
正解
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=210,M=1e3+10;
int n,cnt;
double num,answer,s[N][M],ans[N],q[N],val[N];
string ch,opt;
map<string,int> ma;
inline int read()
{
scanf("%lld",&n);
n++;
for(int i=1;i<=n;i++)
{
scanf("%lf",&num);
cin>>ch;
if(!ma[ch]) ma[ch]=++cnt;
s[i][ma[ch]]=num;
do
{
cin>>opt;
if(opt[0]=='=') break;
scanf("%lf",&num);
cin>>ch;
if(!ma[ch]) ma[ch]=++cnt;
s[i][ma[ch]]=num;
}while(opt[0]!='=');
scanf("%lf",&num);
cin>>ch;
if(!ma[ch]) ma[ch]=++cnt;
s[i][ma[ch]]=-num;
do
{
cin>>opt;
if(opt[0]=='H') break;
scanf("%lf",&num);
cin>>ch;
if(!ma[ch]) ma[ch]=++cnt;
s[i][ma[ch]]=-num;
}while(opt[0]!='H');
if(i!=n) scanf("%lf",&ans[i]);
}
for(int i=1;i<n;i++)
s[i][cnt+1]=ans[i];
}
void gaosi()
{
for(int i=1,j=1;i<n&&j<=cnt;i++,j++)
{
int maxn=i;
for(int k=i+1;k<=n-1;k++)
if(fabs(s[k][j])>fabs(s[maxn][j]))
maxn=k;
if(maxn!=i)
for(int k=1;k<=cnt+1;k++)
swap(s[maxn][k],s[i][k]);
if(!fabs(s[i][j]))
{
i--;
continue;
}
for(int k=i+1;k<=n;k++)
if(fabs(s[k][j]))
{
double temp=s[k][j]/s[i][j];
for(int l=j;l<=cnt+1;l++)
s[k][l]-=s[i][l]*temp;
}
}
}
void solve()
{
gaosi();
printf("%.1lf",-s[n][cnt+1]+1e-12);
}
signed main()
{
read();
solve();
return 0;
}
T3 老司机的狂欢
解题思路
这可真是个阴间题,第一问还比较人性,第二问就变态。
大体思路都是对于序列进行树状数组进行优化。
对于第一问,一看 86400 ,就是二分答案就好了。
对于 \(x(i)<x(j)\) 的情况,需要满足 \(x(i)+\dfrac {a(i)\times t^2}{2} < x(j)+\dfrac {a(j)\times t^2}{2}\)
这好像就是普普通通的物理公式了吧。
那么把x离散作为数组下标,t时间后的位置作为值,合法的最多人数为最长上升子序列。
将t时间后的位置再次离散,并且用树状数组维护。
第二问与第一问差不多,其实就是在模拟第一问的过程,然后记录下最优的 id 。
考虑dp的转移;一个点只能有他之前的一个点转移过来,所以是一个树形结构。
设f[j]=f[k]且都可以转移到i,那么考虑转移的树形结构,j,k处于同一深度,且lca及以上的序列相同。
当j->lca这条路径上的最小值小于k->lca这条路径的最小值时j比k更优。
那么只要倍增维护前驱及最小值即可,同样也是用树状数组进行维护。
code
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
const int N=1e5+10;
int n,m,tim=1,now,tre[N],a[N],lsh[N];
int f[N][25],minn[N][25],ans[N];
pair<int,int> tr[N];
struct Node
{
int x,a,id;
}s[N];
bool comp(Node x,Node y)
{
return x.x<y.x;
}
int lowbit(int x)
{
return x&(-x);
}
void eadd(int x,int num)
{
for(int i=x;i<=n;i+=lowbit(i))
tre[i]=max(tre[i],num);
}
int eask(int x)
{
int maxn=0;
for(int i=x;i>0;i-=lowbit(i))
maxn=max(maxn,tre[i]);
return maxn;
}
bool check(int x)
{
memset(tre,0,sizeof(tre));
for(int i=1;i<=n;i++)
lsh[i]=a[i]=s[i].a*x*x+2*s[i].x;
sort(lsh+1,lsh+n+1);
for(int i=1;i<=n;i++)
{
a[i]=lower_bound(lsh+1,lsh+n+1,a[i])-lsh;
eadd(a[i],eask(a[i]-1)+1);
}
now=eask(n);
return now>=m;
}
void Get_tim()
{
sort(s+1,s+n+1,comp);
int l=1,r=86400;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(mid))
{
l=mid+1;
tim=mid;
}
else r=mid-1;
}
check(tim);
printf("%lld\n",tim);
if(now>m)
{
printf("-1");
exit(0);
}
}
bool judge(pair<int,int> x,pair<int,int> y)
{
if(x.first!=y.first)
return x.first<y.first;
int minx=x.second,miny=y.second,x2=x.second,y2=y.second;
for(int i=20;i>=0;i--)
if(f[x2][i]!=f[y2][i])
{
minx=min(minx,minn[x2][i]);
miny=min(miny,minn[y2][i]);
x2=f[x2][i];
y2=f[y2][i];
}
return minx>miny;
}
void add(int x,pair<int,int> val)
{
for(int i=x;i<=n;i+=lowbit(i))
if(judge(tr[i],val))
tr[i]=val;
}
pair<int,int> ask(int x)
{
pair<int,int> answer=make_pair(0,0);
for(int i=x;i;i-=lowbit(i))
if(judge(answer,tr[i]))
answer=tr[i];
return answer;
}
void build(int x,int fat)
{
f[x][0]=minn[x][0]=fat;
for(int i=1;i<=20;i++)
{
f[x][i]=f[f[x][i-1]][i-1];
minn[x][i]=min(minn[x][i-1],minn[f[x][i-1]][i-1]);
}
}
signed main()
{
memset(minn,0x3f,sizeof(minn));
n=read();
m=read();
for(int i=1;i<=n;i++)
{
s[i].x=read();
s[i].a=read();
s[i].id=i;
}
Get_tim();
for(int i=1;i<=n;i++)
lsh[i]=a[i]=2*s[i].x+s[i].a*tim*tim;
sort(lsh+1,lsh+n+1);
for(int i=1;i<=n;i++)
{
a[i]=lower_bound(lsh+1,lsh+n+1,a[i])-lsh;
pair<int,int> temp=ask(a[i]-1);
build(s[i].id,temp.second);
add(a[i],make_pair(temp.first+1,s[i].id));
}
now=ask(n).second;
for(int i=1;i<=m;i++)
{
ans[i]=now;
now=f[now][0];
}
sort(ans+1,ans+m+1);
for(int i=1;i<=m;i++)
printf("%lld\n",ans[i]);
return 0;
}
7.17考试总结(NOIP模拟18)[导弹袭击·炼金术士的疑惑·老司机的狂欢]的更多相关文章
- 6.17考试总结(NOIP模拟8)[星际旅行·砍树·超级树·求和]
6.17考试总结(NOIP模拟8) 背景 考得不咋样,有一个非常遗憾的地方:最后一题少取膜了,\(100pts->40pts\),改了这么多年的错还是头一回看见以下的情景... T1星际旅行 前 ...
- 2021.9.17考试总结[NOIP模拟55]
有的考试表面上自称NOIP模拟,背地里却是绍兴一中NOI模拟 吓得我直接文件打错 T1 Skip 设状态$f_i$为最后一次选$i$在$i$时的最优解.有$f_i=max_{j<i}[f_j+a ...
- 2021.6.17考试总结[NOIP模拟8]
T1 星际旅行 其实就是求两条只走一遍的边的方案数. 考场上第一眼就感觉不可做,后来画了几个图,发现好像只要两个边是相连的就可以只走一遍,居然还真拿了30.. 其实是一道欧拉路的题,把每条非自环的边看 ...
- Noip模拟18 2021.7.17 (文化课专场)
T1 导弹袭击(数学) 显然,我们要找到最优的A,B使得一组a,b优于其他组那么可以列出: $\frac{A}{a_i}+\frac{B}{b_i}<\frac{A}{a_j}+\frac{B} ...
- 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模拟18
\(\color{white}{\mathbb{曲径通幽,星汉隐约,缥缈灯影,朦胧缺月,名之以:薄雾}}\) 放眼望去前十被我弃掉的 \(t2\) 基本都上85了-- 开考就以为 \(t2\) 是个大 ...
- [考试总结]noip模拟23
因为考试过多,所以学校的博客就暂时咕掉了,放到家里来写 不过话说,vscode的markdown编辑器还是真的很好用 先把 \(noip\) 模拟 \(23\) 的总结写了吧.. 俗话说:" ...
- 2021.7.29考试总结[NOIP模拟27]
T1 牛半仙的妹子图 做法挺多的,可以最小生成树或者最短路,复杂度O(cq),c是颜色数. 我考场上想到了原来做过的一道题影子,就用了并查集,把边权排序后一个个插入,记录权值的前缀和,复杂度mlogm ...
- NOIP 模拟 $18\; \rm 老司机的狂欢$
题解 \(by\;zj\varphi\) 一道很有趣的题,我用的动态开点线段树和倍增 首先对于第一问,不难想到要二分,二分时间,因为时间长一定不会比时间短能跑的人多 那么如何 check,先将所有老司 ...
随机推荐
- 使用树莓派远程控制灯继电器开关,dht11温湿度网页显示,树莓派物联网
前段时间使用esp8266搞了个智能家居,通过网页控制,但是没有办法实现远程控制,只能局域网控制,因为我没有平台,使用机制云等平台还需要开发app 使用chatgpt生成的main.py程序 from ...
- 第五課-Channel Study TCP Listener & Web Service Listener
示例描述: 我们将研究如何获取相当常见的HL7 v2消息并将其映射到自定义Web Service接口服务.在许多实际情况下,当我们要连接到HIE,EMPI,数据仓库或数据存储库时,必须这样做.此用例说 ...
- 为 Serverless Devs 插上 Terraform 的翅膀,实现企业级多环境部署(下)
简介: 在上篇中,主要介绍了 Serverless Devs 多环境功能的使用,用户读完可能会些疑问,本文会就一些常见问题进行下回答. 在上篇中,主要介绍了 Serverless Devs 多环境功能 ...
- Flink SQL 1.11 on Zeppelin 平台化实践
简介: 鉴于有很多企业都无法配备专门的团队来解决 Flink SQL 平台化的问题,那么到底有没有一个开源的.开箱即用的.功能相对完善的组件呢?答案就是本文的主角--Apache Zeppelin. ...
- 阿里云云效发布研发协同工具,以新的产研协同工作方式助力实现BizDevOps
简介:2021云栖大会云效BizDevOps分论坛上,阿里云云效技术负责人陈鑫发布阿里云云效产品研发协同工具支撑ALPD理论,以新的产研协同工作方式助力实现BizDevOps. 编者按:10月21日 ...
- [FAQ] JS 时间戳格式化为 date
拷贝使用,不用引入第三方库 function formatDate (date = 0, fmt = 'yyyy-MM-dd hh:mm:ss') { date = new Date(+date) i ...
- C#类型后加问号?
C# 可空类型(Nullable)说明_w3cschool 细说Nullable<T>类型 - Sweet-Tang - 博客园 (cnblogs.com) 值类型变量不能null,加问号 ...
- SpringMVC拦截器配置后端登录校验
引 创建拦截器的方法有多种,可以继承HandlerInterceptorAdapter类,也可实现HandlerInterceptor接口.接口中有三个方法: preHandle:在业务处理器处理请求 ...
- k8s证书延长时间(二)
1.查看证书有效时间 # 通过下面可看到ca证书有效期是10年,2022-2032 [root@master ~]# openssl x509 -in /etc/kubernetes/pki/ca.c ...
- Linux grep根据关键字匹配前后几行
在Linux环境下,查看文件内容时,很多时候需要查看指定关键字的前后几行,如查看日志文件时,如果日志文件太大,想直接在Linux 终端中查看,可以grep 'partten' filename 进行过 ...