zoukankan      html  css  js  c++  java
  • [CSP-S模拟测试92]题解

    A.数列

    显然每个数的答案是互相独立的,直接扩欧求解。我们需要最小化$ax+by=gcd(a,b)$中的$|x|+|y|$,而显然当x或y靠近0时答案可能最优,列个不等式求一下即可。

    能$O(1)$千万不要懒。

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    using namespace std;
    const int N=1e5+5;
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    	return x*f;
    }
    typedef long long ll;
    int n;
    ll s[N];
    ll x,y,A,B;
    ll gcd(ll a,ll b)
    {
    	if(!b)return a;
    	return gcd(b,a%b);
    }
    ll abss(ll x)
    {
    	return x>0?x:-x;
    }
    void exgcd(ll a,ll b,ll &x,ll &y)
    {
    	if(b==0)
    	{
    		x=1;y=0;return ;
    	}
    	exgcd(b,a%b,x,y);
    	ll t=x;x=y;y=t-a/b*y;
    }
    void test()
    {
    	A=read();B=read();int G=gcd(A,B);
    	cout<<G<<endl;
    	exgcd(A,B,x,y);
    	cout<<x<<' '<<y<<endl;
    }
    int main()
    {
    	//freopen("array.in","r",stdin);
    	n=read();A=read();B=read();
    	for(int i=1;i<=n;i++)
    		s[i]=read();
    	ll ans=0;ll G=gcd(A,B),ta=A/G,tb=B/G;
    	exgcd(A/G,B/G,x,y);
    
    	for(int i=1;i<=n;i++)
    	{
    		if(s[i]%G!=0)
    		{
    			puts("-1");
    			exit(0);
    		}
    		ll res=1e15;
    
    		ll t=s[i]/G;
    		ll nowx=x*t,nowy=y*t;
    		res=min(res,abss(nowx)+abss(nowy));
    		ll p=-nowx/tb;
    		res=min(res,abss(nowx+p*tb)+abss(nowy-p*ta));
    		res=min(res,abss(nowx+(p-1)*tb)+abss(nowy-(p-1)*ta));
    		res=min(res,abss(nowx+(p+1)*tb)+abss(nowy-(p+1)*ta));
    		p=-nowy/ta;
    		res=min(res,abss(nowx-p*tb)+abss(nowy+p*ta));
    		res=min(res,abss(nowx-(p-1)*tb)+abss(nowy+(p-1)*ta));
    		res=min(res,abss(nowx-(p+1)*tb)+abss(nowy+(p+1)*ta));
    
    		//cout<<nowx<<' '<<nowy<<endl;
    		ans+=res;
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    B.数对

    可任意排序看似难以解决,但考虑一下$a$和$b$之间的限制,不难发现如果$a_i<b_j and b_i<a_j$,$i$应当尽可能在$j$前面,如果恰好相反那么$i$就应该在后面,至于剩下的情况,怎么排都是一样的。那么按$a+b$排序就能保证选取一定最优。

    之后就是原题了。线段树维护dp板子。

    (忽然发现我好像没写过之前那题的题解 懒癌发作失败)

    那么现在问题就转化成了给你一个二元组序列,要求你按顺序选几个二元组,在满足所有$a_i leq b_j (i<j)$的情况下最大化权值。

    设$dp[i][j]$表示当前考虑到i并且选了它,且所选集合中最大的$a[]$值为j的最大收益。($a[]$和$b[]$当然是要离散化的= =)

    暴力$O(n^3)$转移就很显然了:

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std;
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    	return x*f;
    }
    const int N=1e5+5;
    typedef long long ll;
    int n,a[N],b[N],S;
    
    ll w[N],dp[2505][2505],ans;
    vector<int> c;
    struct node
    {
    	int a,b;ll w;
    }s[N];
    bool cmp(node x,node y)
    {
    	if(max(x.b,x.a)!=max(y.b,y.a))
    		return max(x.b,x.a)<max(y.b,y.a);
    	else return x.b<y.a;
    }
    int main()
    {
    	//freopen("pair.in","r",stdin);
    	n=read();
    	for(int i=1;i<=n;i++)
    		s[i].a=read(),s[i].b=read(),s[i].w=read();
    	sort(s+1,s+n+1,cmp);
    	for(int i=1;i<=n;i++)
    		a[i]=s[i].a,b[i]=s[i].b,c.push_back(a[i]),c.push_back(b[i]),w[i]=s[i].w;
    	sort(c.begin(),c.end());vector<int>::iterator it=unique(c.begin(),c.end());
    	for(int i=1;i<=n;i++)
    	{
    		a[i]=lower_bound(c.begin(),it,a[i])-c.begin()+1;
    		b[i]=lower_bound(c.begin(),it,b[i])-c.begin()+1;
    		S=max(S,max(a[i],b[i]));
    	}
    	for(int i=1;i<=n;i++)
    	{
    		dp[i][a[i]]=w[i];
    		for(int j=1;j<i;j++)
    			for(int k=1;k<=b[i];k++)
    				dp[i][max(k,a[i])]=max(dp[i][max(k,a[i])],dp[j][k]+w[i]),ans=max(ans,dp[i][max(a[i],k)]);
    	}
    
    	cout<<ans<<endl;
    	return 0;
    }
    

    然后你发现可以直接把第二维扔到线段树上维护,区间修改区间查询单点更新即可。

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std;
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    
    
    const int N=1e5+5;
    typedef long long ll;
    int n,a[N],b[N],S;
    
    ll w[N],dp[N],ans;
    vector<int> c;
    struct node
    {
        int a,b;ll w;
    }s[N];
    bool cmp(node x,node y)
    {
        return (x.a+x.b)<(y.a+y.b);
    }
    
    ll maxv[N<<3],lz[N<<3];
    #define ls(k) (k)<<1
    #define rs(k) (k)<<1|1
    #define up maxv[k]=max(maxv[ls(k)],maxv[rs(k)])
    void down(int k)
    {
        if(!lz[k])return ;
        lz[ls(k)]+=lz[k];
        lz[rs(k)]+=lz[k];
        maxv[ls(k)]+=lz[k];
        maxv[rs(k)]+=lz[k];
        lz[k]=0;
    }
    void update(int k,int l,int r,int pos,ll val)
    {
        if(l==r)
        {
            maxv[k]=max(maxv[k],val);
            return ;
        }
        down(k);
        int mid=l+r>>1;
        if(pos<=mid)update(ls(k),l,mid,pos,val);
        else update(rs(k),mid+1,r,pos,val);
        up;
    }
    ll ask(int k,int l,int r,int L,int R)
    {
        if(l>r)return 0;
        if(L<=l&&R>=r)return maxv[k];
        down(k);
        int mid=l+r>>1;ll res=0;
        if(L<=mid)res=max(res,ask(ls(k),l,mid,L,R));
        if(R>mid)res=max(res,ask(rs(k),mid+1,r,L,R));
        return res;
    }
    void change(int k,int l,int r,int L,int R,ll val)
    {
        if(l>r)return ;
        if(L<=l&&R>=r)
        {
            maxv[k]+=val;
            lz[k]+=val;
            return ;
        }
        down(k);
        int mid=l+r>>1;
        if(L<=mid)change(ls(k),l,mid,L,R,val);
        if(R>mid)change(rs(k),mid+1,r,L,R,val);
        up;
    }
    
    int main()
    {
        //freopen("pair.in","r",stdin);
        n=read();
        for(int i=1;i<=n;i++)
            s[i].a=read(),s[i].b=read(),s[i].w=read();
        sort(s+1,s+n+1,cmp);
        for(int i=1;i<=n;i++)
            a[i]=s[i].a,b[i]=s[i].b,c.push_back(a[i]),c.push_back(b[i]),w[i]=s[i].w;
        sort(c.begin(),c.end());vector<int>::iterator it=unique(c.begin(),c.end());
        for(int i=1;i<=n;i++)
        {
            a[i]=lower_bound(c.begin(),it,a[i])-c.begin()+1;
            b[i]=lower_bound(c.begin(),it,b[i])-c.begin()+1;
            S=max(S,max(a[i],b[i]));
        }
        for(int i=1;i<=n;i++)
        {
            if(a[i]>b[i])
                dp[i]=max(dp[i],ask(1,1,S,1,b[i])+w[i]);
            else
            {
                dp[i]=max(dp[i],ask(1,1,S,1,a[i])+w[i]);
                change(1,1,S,a[i],b[i],w[i]);
            }
            update(1,1,S,a[i],dp[i]);
        }
    
        cout<<ask(1,1,S,1,S)<<endl;
        return 0;
    }
    

    C.最小距离

    什么?dj可以跑多源最短路?

    一开始把所有特殊点都扔到堆里,转移的时候记录该点由哪个特殊点转移过来,最后枚举边把答案拼一下就好了。

    因为每个点只会被更新一次,所以跑出来每个点的$dis[]$必然为离它最近的那个特殊点的距离。枚举边的时候,如果两端不是同一个点转移而来,就可以用两个$dis[]$+边权更新答案。

    #include<bits/stdc++.h>
    using namespace std;
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    #define pa pair<ll,int>
    const int N=2e5+5;
    typedef long long ll;
    int n,m,p;
    bool isp[N];
    int to[N<<1],head[N],nxt[N<<1],vis[N],sp[N],tot,fr[N];
    ll w[N<<1],ans[N<<1],dis[N];
    void add(int x,int y,ll z)
    {
        to[++tot]=y;
        nxt[tot]=head[x];
        head[x]=tot;
        w[tot]=z;
    }
    void dj()
    {
        priority_queue<pa> q;
        for(int i=1;i<=n;i++)
            dis[i]=1e15,vis[i]=0;
        for(int i=1;i<=p;i++)
            q.push(make_pair(0,sp[i])),fr[sp[i]]=sp[i],dis[sp[i]]=0;
        while(!q.empty())
        {
            int x=q.top().second;q.pop();
            if(vis[x])continue;
            vis[x]=1;
            for(int i=head[x];i;i=nxt[i])
            {
                int y=to[i];
                if(dis[y]>dis[x]+w[i])
                    dis[y]=dis[x]+w[i],fr[y]=fr[x],q.push(make_pair(-dis[y],y));
            }
        }
        for(int i=1;i<=m;i++)
        {
            int x=to[i*2-1],y=to[i*2];
            if(fr[x]!=fr[y])
            {
                ans[fr[x]]=min(ans[fr[x]],dis[x]+w[i*2]+dis[y]);
                ans[fr[y]]=min(ans[fr[y]],dis[x]+w[i*2]+dis[y]);
            }
        }
    }
    int main()
    {
        n=read();m=read();p=read();
        for(int i=1;i<=p;i++)
        {
            int x=read();
            sp[i]=x;
            isp[x]=1;
        }
        for(int i=1;i<=n;i++)
            ans[i]=1e15;
        for(int i=1;i<=m;i++)
        {
            int x=read(),y=read();ll z=read();
            add(x,y,z);add(y,x,z);
        }
        dj();
        for(int i=1;i<=p;i++)
            printf("%lld ",ans[sp[i]]);
        return 0;
    }
    
  • 相关阅读:
    腾讯云 ubuntu 上tomcat加载项目很慢
    ubuntu 中iptables
    linux ssh修改 默认22端口
    jetty 客服端 与服务端
    spring mvc 拦截器
    linux配置iptables(3)
    el取bean 对象属性规则
    mybatis 反射bean规则
    fastjson tojson部分规则
    正则获取参数 分组
  • 原文地址:https://www.cnblogs.com/Rorschach-XR/p/11758607.html
Copyright © 2011-2022 走看看