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,先将所有老司 ...
随机推荐
- 力扣441(java&python)-排列硬币(简单)
题目: 你总共有 n 枚硬币,并计划将它们按阶梯状排列.对于一个由 k 行组成的阶梯,其第 i 行必须正好有 i 枚硬币.阶梯的最后一行 可能 是不完整的. 给你一个数字 n ,计算并返回可形成 完整 ...
- 5G 和云原生时代的技术下半场,视频化是最大最新的确定性
------------恢复内容开始------------ null ------------恢复内容结束------------
- 「现代C++设计魅力」虚函数继承-thunk技术初探
简介:工作中使用LLDB调试器调试这一段C++多继承程序的时候,发现通过lldb print(expression命令的别名) 命令获取的指针地址和实际理解的C++的内存模型的地址不一样.那么到底是什 ...
- [FAQ] Goland 始终没有包代码的提示 ?
表现:import 引入的包始终是红色的,表示没有找到引入的包. 注意,在这里开启Go Modules: 然后在 Exteneral Libraries 里看到 Go Modules 即可. Refe ...
- [SVG] JS 动态加载 svg 修改 svg 属性
svg 概念一览: https://javascript.ruanyifeng.com/htmlapi/svg.html加载 svg: // for example: $('body').load(' ...
- [Go] golang 时间格式化 12小时制 与 24小时制
timestamp := int64(1591271169) # 12小时制 time.Unix(timestamp, 0).Format("2006-01-02 03:04:05" ...
- dotnet 警惕判断文件是否存在因为检查网络资源造成超长等待
在使用 System.IO.File.Exists 方法时,绝大部分的情况下都是一个非常快捷且没有成本的,但是如果判断的文件是否存在,是从非自己完全控制的逻辑下进入的,那就需要警惕是否判断的文件路径属 ...
- WPF 创建空白图片
本文告诉大家如何在 WPF 创建空白图片,可以创建1像素图片 可以使用 BitmapSource 的 Create 方法创建空白图片 // 限制不能创建小于2x2的图片 const int width ...
- 2018-11-23-国内好用的-DNS-列表
title author date CreateTime categories 国内好用的 DNS 列表 lindexi 2018-11-23 12:45:57 +0800 2018-11-23 12 ...
- Winform程序使用app.minifest清单禁止高DPI无法失效问题
问题:Winform程序使用app.minifest清单禁止高DPI无法失效问题 摘要:因为笔记本基本都会有DPI放大,所以目前程序需要嵌入清单,并将其高DPI支持给禁止掉. 环境搭建:Winform ...