zoukankan      html  css  js  c++  java
  • CSP-S 模拟75

      不是一道题不会,是一道题都不会,全是暴力,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<iostream>
    #include<cstdio>
    #include<algorithm>
    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]);
    }
    View Code

      炼金术士的疑惑

        高斯消元

        读入很麻烦,但是其它挺简单的,主要是考察了对于高斯消元的理解

        将n个方程读入,第n+1个的询问读入,然后跑一遍高斯消元,高斯消元的过程就是将方程代入其他方程的过程,所以将n个方程消元的过程中代入询问方程并消去询问方程的系数,假设原来询问方程的焓变值为H,消元完之后会变成0,而现在初值是0,那么H就等于最后询问方程的答案的相反数

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    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])<eps) 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])<eps) puts("0.0");
        else printf("%.1lf
    ",-a[n+1][tot+1]);
    }
    View Code

      老司机的狂欢

        主要在于题意转换

        将老司机的初始位置为x,按x从大到小排序,若t秒后老司机不相遇或追及,那么老司机的最终位置还是有序的,即LIS问题,用树状数组维护

        考虑随时间递增,不会相遇的老司机数量会单调递减,可以二分时间,找到k个老司机不相遇的时间t,如果最终二分出的时间算出来有多于k个老司机可以不相遇,那么老司机就要有意见了,输出t后puts("-1")

        如果恰好k个老司机的话,需要求出最小字典序的方案,看求LIS过程,是从前面的某一个位置小于我而序列长度最大的转移到我,类似与一棵树的样子找深度最大的权值小于我的点连边

        如果有两个点满足深度都是最大的,且权值(最终位置)都小于我的,那么求两个点的lca选取点到lca的路径上最小id最小的那个点连边

        因为考虑输出按id排序之后字典序最小,如果最小id最小,那么这条链必定比最小id大的字典序小

        最后找k深度的字典序最小的那条树上从叶子节点到根的链,按id排序后输出即可

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    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<<i)<=dis[y];i++);
        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<b.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
    ",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
    ",st[i]);
        }
    }
    View Code
  • 相关阅读:
    Windows快捷键
    visual studio code颜色主题切换
    visual studio code中文语言包安装
    顶点缓存与索引缓存
    程序结构(2)
    ansible常用模块
    ansible常用模块
    ubuntu实用技巧
    ubuntu实用技巧
    Sqoop导出MySQL数据
  • 原文地址:https://www.cnblogs.com/heoitys/p/11686681.html
Copyright © 2011-2022 走看看