• 2018.8.6 模拟赛 提高组B


    T1
    Description

    给定一个n个点m条边的有向图,有k个标记点,要求从规定的起点按任意顺序经过所有标记点到达规定的终点,问最短的距离是多少。

    Input

    第一行5个整数n、m、k、s、t,表示点个数、边条数、标记点个数、起点编号、终点编号。

    接下来m行每行3个整数x、y、z,表示有一条从x到y的长为z的有向边。

    接下来k行每行一个整数表示标记点编号。

    Output

    输出一个整数,表示最短距离,若没有方案可行输出-1。

    Sample Input

    3 3 2 1 1

    1 2 1

    2 3 1

    3 1 1

    2

    3

    Sample Output

    3

    【样例解释】

    路径为1->2->3->1。

    Data Constraint

    20%的数据n<=10。

    50%的数据n<=1000。

    另有20%的数据k=0。

    100%的数据n<=50000,m<=100000,0<=k<=10,1<=z<=5000。

    解题思路

    考场上一时抽风写了个最短路套状压初值还没附好,50分。。正解应该是将必须经过的点两两之间的最短路求出来之后dfs

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #define int long long
    
    using namespace std;
    const int MAXN = 50005;
    const int inf = 0x3f3f3f3f3f3f3f3f;
    
    int n,m,k,S,T,go[MAXN],ans=0x3f3f3f3f3f3f3f3f;
    int head[MAXN],cnt,tot;
    int to[MAXN<<1],nxt[MAXN<<1],val[MAXN<<1];
    int dis[15][MAXN],id[MAXN],dp[(1<<11)+5][15];
    bool vis[MAXN],must[MAXN],use[MAXN];
    queue<int> Q;
    
    inline int rd(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch))  {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
        return x*f;
    }
    
    inline void add(int bg,int ed,int w){
        to[++cnt]=ed,nxt[cnt]=head[bg],head[bg]=cnt,val[cnt]=w;
    }
    
    inline void spfa(int x){
        memset(vis,false,sizeof(vis));
        dis[++tot][x]=0;vis[x]=1;Q.push(x);
        while(!Q.empty()){
            int x=Q.front();Q.pop();
            for(register int i=head[x];i;i=nxt[i]){
                int u=to[i];
                if(dis[tot][x]+val[i]<dis[tot][u]) {
                    dis[tot][u]=dis[tot][x]+val[i];
                    if(!vis[u]) {
                        vis[u]=1;
                        Q.push(u);
                    }
                }
            }
            vis[x]=0;
        }
    }
    
    inline void dfs(int x,int now,int sum){
        if(sum>ans) return;
        if(now==k) {ans=min(ans,sum+dis[id[x]][T]);return;}
        for(register int i=1;i<=k;i++){
            if(use[i]) continue;
            use[i]=1;
            dfs(go[i],now+1,sum+dis[id[x]][go[i]]);
            use[i]=0;
        }
    }
    
    signed main(){
        memset(dp,0x3f,sizeof(dp));
        memset(dis,0x3f,sizeof(dis));
        n=rd();m=rd();k=rd();S=rd();T=rd();
        for(register int i=1;i<=m;i++){
            int x=rd(),y=rd(),z=rd();
            add(x,y,z);
        }
        for(register int i=1;i<=k;i++){
            int x=rd();must[x]=1;id[x]=i;go[i]=x;
            spfa(x);
        }
        if(!must[S]) spfa(S),id[S]=k+1;
        for(register int i=1;i<=k;i++){
            memset(use,false,sizeof(use));
            if(dis[id[S]][go[i]]==inf) continue;
            use[i]=1;
            if(must[S] && go[i]!=S) 
                dfs(go[i],2,dis[id[S]][go[i]]);
            else if(!must[S])
                dfs(go[i],1,dis[id[S]][go[i]]);
        }
        if(k==0) ans=dis[id[S]][T];
        if(ans==inf) ans=-1; 
        cout<<ans<<endl;
        return 0;
    }

    T2

    Description

    万老师听说某大国很流行穿越,于是他就想写一个关于穿越的剧本。

    闲话休提。话说老师穿越到了某一个剑与魔法的大陆。因为如此这般,所以老师从维娜艾那里得到了预言。老师一共被告知了若干件按顺序结算的事件。这些事件分为两类:战役事件(CASE)、穿越回去事件(END)。战役事件可以选择是否参加,参加了之后会获得一定的金钱。每个END事件发生需要至少参加一定数量的战役事件。特别的是,END事件如果满足要求就会强制发生。老师希望在大陆玩个够,所以他要求只有最后一个END事件会发生。老师希望获得最多的金钱,所以求助于你。

    Input

    第一行一个数N,表示输入文件有多少行。

    接下来每一行用空格隔开一个字符和一个整数。字符为“c”表示战役事件,接下来的整数表示这次涨RP顺带有多少钱;字符为“e”表示穿越回去事件,接下来的整数代表至少要涨多少RP。最后一个事件保证是END事件。

    Output

    第一行一个整数,最多金钱数目。

    若不可能则输出-1。

    Sample Input

    5

    c 10

    c 12

    e 2

    c 1

    e 2

    Sample Output

    13

    Data Constraint

    30%的数据满足 N<=20

    60%的数据满足 N<=1,000

    100%的数据满足 N<=200,000

    每次涨RP事件赏金不超过10,000

    穿越事件的要求不超过200,000

    解题思路

    最后的战役事件竟然能超了最后的end!!!我太菜了还以为能相等。。。写了两个小时的线段树+对拍结果0分。。又是一道由100 变成 0的好题。正解是优先队列+贪心。我用的线段树直接先排序,然后每次挑最大的相当于区间修改,从这个战役之后的第一个一直到倒数第二个这段区间-1。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    
    using namespace std;
    const int MAXN = 200005;
    const int inf = 0x3f3f3f3f;
    
    int n,cnt1,cnt2,ans,mn[MAXN<<1];
    int sum[MAXN<<1],lazy[MAXN<<1];
    
    struct Data{
        int id,a;
    }data[3][MAXN];
    
    inline int rd(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch))  {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
        return x*f;
    }
    
    inline bool cmp(Data A,Data B){
        return A.a>B.a;
    }
    
    inline void pushdown(int x,int ln,int rn){
        lazy[x<<1]+=lazy[x];
        lazy[x<<1|1]+=lazy[x];
        sum[x<<1]+=ln*lazy[x];
        sum[x<<1|1]+=rn*lazy[x];
        mn[x<<1]+=lazy[x];
        mn[x<<1|1]+=lazy[x];
        lazy[x]=0;
    }
    
    inline void build(int x,int l,int r){
        if(l==r){
            sum[x]=data[2][l].a;
            mn[x]=data[2][l].a;
            lazy[x]=0;
            return ;
        }
        int mid=l+r>>1;
        build(x<<1,l,mid);
        build(x<<1|1,mid+1,r);
        sum[x]=sum[x<<1]+sum[x<<1|1];
        mn[x]=min(mn[x<<1],mn[x<<1|1]);
    }
    
    inline void update(int x,int l,int r,int L,int R,int k){
        if(L<=l && r<=R){
            sum[x]+=k;mn[x]+=k;lazy[x]+=k;
            return ;
        }
        int mid=l+r>>1;
        if(lazy[x]) pushdown(x,mid-l+1,r-mid);
        if(mid>=L) update(x<<1,l,mid,L,R,k);
        if(mid<R)  update(x<<1|1,mid+1,r,L,R,k);
        sum[x]=sum[x<<1]+sum[x<<1|1];
        mn[x]=min(mn[x<<1],mn[x<<1|1]);
    }
    
    inline int query(int x,int l,int r,int L,int R){
        if(L<=l && r<=R) return mn[x];
        int ret=0x3f3f3f3f;
        int mid=l+r>>1;
        if(lazy[x]) pushdown(x,mid-l+1,r-mid);
        if(mid>=L) ret=min(ret,query(x<<1,l,mid,L,R));
        if(mid<R)  ret=min(ret,query(x<<1|1,mid+1,r,L,R));
        return ret;
    }
    
    int main(){
        n=rd();
        for(register int i=1;i<=n;i++){
            char c;cin>>c;int x=rd();
            if(c=='c') data[1][++cnt1].a=x,data[1][cnt1].id=i;
            else  data[2][++cnt2].a=x,data[2][cnt2].id=i;
        }
        build(1,1,cnt2);
        sort(data[1]+1,data[1]+1+cnt1,cmp);
        for(register int i=1;i<=cnt1;i++){
            int ID=data[1][i].id;int x=data[1][i].a;
            int l=1,r=cnt2;int now;
            while(l<=r){
                int mid=l+r>>1;
                if(data[2][mid].id<ID) l=mid+1;
                else {
                    now=mid;
                    r=mid-1;
                }
            }
            int res;
            if(now>cnt2-1) res=inf;
            else res=query(1,1,cnt2,now,cnt2-1); 
            if(res>1 || now==cnt2){
                ans+=x;
                if(now!=cnt2)
                    update(1,1,cnt2,now,cnt2-1,-1);
            }
        }
        cout<<ans<<endl;
        return 0;
    }

    T3
    Time Limits: 1000 ms Memory Limits: 262144 KB Detailed Limits
    Goto ProblemSet

    Description

    平面上有n个点,求出用这些点可以构成的三角形数。

    Input

    第一行一个整数n。

    接下来n行,每行两个整数,表示点的坐标。

    Output

    输出仅一个整数,表示所求答案。

    Sample Input

    5

    0 0

    1 1

    1 -1

    -1 -1

    -1 1

    Sample Output

    8

    Data Constraint

    对于50%的数据,n<=300。

    对于100%的数据,n<=3000,坐标的绝对值不超过10^4,保证没有重合的点。

    解题思路

    这道题跟以前做过的数三角形好像啊,结果还是打的暴力。。用容斥的思想,每次枚举一个点,然后枚举其余点算斜率,之后排个序用组合数学。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<cstdlib>
    #include<algorithm>
    #define int long long
    
    using namespace std;
    const int MAXN = 3005;
    const double inf = 1e10+1;
    const double eps = 1e-12;
    
    int n,x[MAXN],y[MAXN],sum,cnt;
    double slp[MAXN];
    
    inline int rd(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch))  {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
        return x*f;
    }
    
    signed main(){
        freopen("triangle.in","r",stdin);
        freopen("triangle.out","w",stdout);
        n=rd();sum=n*(n-1)*(n-2)/6;
        for(register int i=1;i<=n;i++)
            x[i]=rd(),y[i]=rd();
        for(register int i=1;i<=n;i++){
            memset(slp,0,sizeof(slp));cnt=0;
            for(register int j=i+1;j<=n;j++){
                if(y[i]==y[j]) slp[++cnt]=inf;
                else if(x[i]==x[j]) slp[++cnt]=-inf;
                else slp[++cnt]=(double)(x[i]-x[j])/(y[i]-y[j]);
            } 
            sort(slp+1,slp+1+cnt);
            int now=1;slp[0]=-inf-5;
            for(register int j=1;j<=cnt;j++){
                if(fabs(slp[j]-slp[j-1])>eps){
                    sum-=now*(now-1)/2;
                    now=1;
                }
                else now++;
            }
            sum-=now*(now-1)/2;
        }
        printf("%lld",sum);
        return 0;
    }
  • 相关阅读:
    JSOI2015 R3 退队滚粗了
    bzoj3774
    bzoj1426
    bzoj3294
    java 位向量
    java 移位操作
    java 枚举类型的使用
    mysql 修改 root 用户密码
    几种数据库连接池的比较
    linux python 安装 pip出现 No module named 'setuptools'
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/9676903.html
Copyright © 2020-2023  润新知