不是一道题不会,是一道题都不会,全是暴力,T1高考数学,T2高斯消元早忘了,高考化学没学好,T3高考物理没学好
导弹袭击
推式子,设其他导弹的速度为(x,y),有用的导弹(a,b)必须满足 存在$\frac{A}{a}+\frac{B}{b}<=min(\frac{A}{x}+\frac{B}{y}) $
直接照着式子打n^2做法,可以拿55~65分
我们将$a=\frac{1}{a},b=\frac{1}{b},x=\frac{1}{x},y=\frac{1}{y}$,那么我们就是求 $Z=Aa+Bb$最小
转换成函数形式$y=-\frac{A}{B}x+\frac{Z}{B}$ ,因为A,B为正实数,所以问题转化为求出是否存在一个斜率使得函数过$(a,b)$点的时候纵截距最小
所以把$(x,y)$转换成二维坐标系上的点$(\frac{1}{x},\frac{1}{y})$,跑一个下凸包就可以了
注意细节:跑凸包前先把所有不可能的点咕咕掉!
#include#include #include using namespace std; int n,st[310000],to[310000]; struct node{ long double a,b; int id; bool operator < (const node x)const{ return (a>x.a)||(a==x.a&&b>x.b); } }w[310000]; long double cal(int x,int y){ if(w[y].a==w[x].a) return 1; if(w[y].b==w[x].b) return 1; return w[x].a/w[x].b*w[y].a/w[y].b*(w[x].b-w[y].b)/(w[x].a-w[y].a); } int main(){ //freopen("slay4.in","r",stdin); scanf("%d",&n); for(register int i=1;i<=n;i++) scanf("%LF%LF",&w[i].a,&w[i].b),w[i].id=i; sort(w+1,w+n+1); int num=0; for(register int i=1;i<=n;i++){ if(w[i].a==w[i-1].a&&w[i].b==w[i-1].b){ to[w[i-1].id]=w[i].id; } else{ w[++num].a=w[i].a,w[num].b=w[i].b; w[num].id=w[i].id; } } n=num; sort(w+1,w+n+1); st[++st[0]]=1; for(register int i=2;i<=n;i++){ if(cal(st[st[0]],i)>0) continue; while(st[0]>1&&cal(st[st[0]-1],st[st[0]])-cal(st[st[0]],i)>1e-30) st[0]--; st[++st[0]]=i; } num=st[0]; for(register int i=1;i<=st[0];i++){ st[i]=w[st[i]].id; for(register int j=to[st[i]];j;j=to[j]) st[++num]=j; } st[0]=num; sort(st+1,st+st[0]+1); for(register int i=1;i<=st[0];i++) printf("%d ",st[i]); }
炼金术士的疑惑
高斯消元
读入很麻烦,但是其它挺简单的,主要是考察了对于高斯消元的理解
将n个方程读入,第n+1个的询问读入,然后跑一遍高斯消元,高斯消元的过程就是将方程代入其他方程的过程,所以将n个方程消元的过程中代入询问方程并消去询问方程的系数,假设原来询问方程的焓变值为H,消元完之后会变成0,而现在初值是0,那么H就等于最后询问方程的答案的相反数
#include#include #include #include using namespace std; int n,tot; char h[20]; const long long mod=233333; const double eps=1e-6; double a[210][210],b[210]; struct node{ int ha[233333]; int insert(){ int len=strlen(h+1); long long sta=0; for(register int i=1;i<=len;i++){ sta=(1ll*sta*33%mod+h[i])%mod; } if(!ha[sta]) ha[sta]=++tot; return ha[sta]; } }H; void Gauss(){ for(register int i=1;i<=n;i++){ int p=i; for(register int j=i+1;j<=n;j++) if(fabs(a[j][i])>fabs(a[p][i])) p=j; for(register int j=1;j<=tot+1;j++) swap(a[i][j],a[p][j]); if(fabs(a[i][i]) continue; double tmp=a[i][i]; for(register int j=1;j<=tot+1;j++) a[i][j]/=tmp; for(register int j=1;j<=n+1;j++){ tmp=a[j][i]; if(i==j) continue; for(register int k=1;k<=tot+1;k++){ a[j][k]-=a[i][k]*tmp; } } } } void init(int t){ double x; while(1){ scanf("%lf%s",&x,h+1); int sta=H.insert(); a[t][sta]=x; scanf("%s",h+1); if(h[1]=='=') break; } while(1){ scanf("%lf%s",&x,h+1); int sta=H.insert(); a[t][sta]=-x; scanf("%s",h+1); if(h[1]=='H') break; } if(t==n+1) return; scanf("%lf",&b[t]); } int main(){ scanf("%d",&n); for(register int i=1;i<=n;i++) init(i); n=max(n,tot); tot=n; init(n+1); for(register int i=1;i<=n+1;i++) a[i][tot+1]=b[i]; Gauss(); if(fabs(a[n+1][tot+1]) "0.0"); else printf("%.1lf\n",-a[n+1][tot+1]); }
老司机的狂欢
主要在于题意转换
将老司机的初始位置为x,按x从大到小排序,若t秒后老司机不相遇或追及,那么老司机的最终位置还是有序的,即LIS问题,用树状数组维护
考虑随时间递增,不会相遇的老司机数量会单调递减,可以二分时间,找到k个老司机不相遇的时间t,如果最终二分出的时间算出来有多于k个老司机可以不相遇,那么老司机就要有意见了,输出t后puts("-1")
如果恰好k个老司机的话,需要求出最小字典序的方案,看求LIS过程,是从前面的某一个位置小于我而序列长度最大的转移到我,类似与一棵树的样子找深度最大的权值小于我的点连边
如果有两个点满足深度都是最大的,且权值(最终位置)都小于我的,那么求两个点的lca选取点到lca的路径上最小id最小的那个点连边
因为考虑输出按id排序之后字典序最小,如果最小id最小,那么这条链必定比最小id大的字典序小
最后找k深度的字典序最小的那条树上从叶子节点到根的链,按id排序后输出即可
#include#include #include #include using namespace std; int n,k,st[110000],fa[110000][20],minn[110000][20],dis[110000]; struct node{ long long x,a,pos; int id; bool operator < (const node b)const{ return x<b.x; } }w[110000]; long long tmp[110000]; pair<int,int>tr[110000]; char lca(int x,int y){ int minnx=x,minny=y; int i=0; for(;(1<); for(register int j=i;j>=0;j--){ if(fa[y][j]!=fa[x][j]){ minnx=min(minnx,minn[x][j]); minny=min(minny,minn[y][j]); x=fa[x][j]; y=fa[y][j]; } } return minnx<minny; } pair<int,int>askmax(pair<int,int>a,pair<int,int>b){ if(a.first return b; else if(a.first>b.first) return a; if(lca(a.second,b.second)) return a; return b; } int lowbit(int x){return x&(-x);} void add(int x,pair<int,int>w){ while(x<=n+1){ tr[x]=max(tr[x],w); x+=lowbit(x); } } pair<int,int> ask(int x){ pair<int,int>ans=make_pair(0,0); while(x){ ans=max(ans,tr[x]); x-=lowbit(x); } return ans; } int judge(long long mid){ tmp[0]=0; for(register int i=1;i<=n;i++){ w[i].pos=w[i].x+w[i].a*mid*mid/2; tmp[++tmp[0]]=w[i].pos; } sort(tmp+1,tmp+tmp[0]+1); tmp[0]=unique(tmp+1,tmp+tmp[0]+1)-tmp-1; for(register int i=1;i<=n;i++) w[i].pos=lower_bound(tmp+1,tmp+tmp[0]+1,w[i].pos)-tmp; for(register int i=1;i<=n+1;i++) tr[i]=make_pair(0,0); for(register int i=1;i<=n;i++){ pair<int,int> cet=ask(w[i].pos); cet.first++;cet.second=w[i].id; add(w[i].pos+1,cet); } pair<int,int>cet=ask(n+1); return cet.first; } void buildadd(int x,pair<int,int>w){ while(x<=n+1){ tr[x]=askmax(tr[x],w); x+=lowbit(x); } } pair<int,int> buildask(int x){ pair<int,int>ans=make_pair(0,0); while(x){ ans=askmax(ans,tr[x]); x-=lowbit(x); } return ans; } void build(){ for(register int i=1;i<=n+1;i++) tr[i]=make_pair(0,0); memset(fa,0,sizeof(fa)); memset(minn,0x3f,sizeof(minn)); for(register int i=1;i<=n;i++){ pair<int,int> cet=buildask(w[i].pos); fa[w[i].id][0]=cet.second; minn[w[i].id][0]=cet.second; dis[w[i].id]=dis[cet.second]+1; for(register int j=1;j<=16;j++){ fa[w[i].id][j]=fa[fa[w[i].id][j-1]][j-1]; minn[w[i].id][j]=min(minn[w[i].id][j-1],minn[fa[w[i].id][j-1]][j-1]); } cet.first++;cet.second=w[i].id; buildadd(w[i].pos+1,cet); } } int main(){ //freopen("driver3.in","r",stdin); //freopen("3.out","w",stdout); scanf("%d%d",&n,&k); for(register int i=1;i<=n;i++) scanf("%lld%lld",&w[i].x,&w[i].a),w[i].id=i; sort(w+1,w+n+1); int l=0,r=86400,mid,ans; while(l<=r){ mid=(l+r)>>1; if(judge(mid)>=k) ans=mid,l=mid+1; else r=mid-1; } printf("%d\n",ans); if(judge(ans)>k) puts("-1"); else{ build(); int x=buildask(n+1).second; st[++st[0]]=x; while(fa[x][0]!=0){ x=fa[x][0]; st[++st[0]]=x; } sort(st+1,st+st[0]+1); for(register int i=1;i<=st[0];i++) printf("%d\n",st[i]); } }