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

    话说我怎么觉得我没咕多长时间啊,怎么就又落了20多场题解啊

    T1 array:

    根据题意不难列出二元一次方程,于是可以用exgcd求解,然而还有一个限制条件就是$abs(x)+abs(y)$最小,这好像很难搞,但是我们用exgcd求出一组特解之后的通解公式是个一次函数,通过手玩可知x,y只可能是最小正整数或最大负整数解,这就很好整,时间复杂度$O(n)$,当然也可以三分。

     1 #include<bits/stdc++.h>
     2 #define int long long
     3 using namespace std;
     4 const int N=1e5+10;
     5 void exgcd(int a,int b,int &x,int &y,int &gcd){//ax+by=c,gcd wei gongyueshu
     6     if(!b){
     7         gcd=a;
     8         x=1;
     9         y=0;
    10     }
    11     else{
    12         exgcd(b,a%b,y,x,gcd);
    13         y-=a/b*x;
    14     }
    15 }
    16 int gcd(int a,int b){
    17     return (!b)?a:gcd(b,a%b);
    18 }
    19 int solve(int a,int b,int x,int y,int k,int g){
    20     //cout<<"a=="<<a<<" b=="<<b<<" k=="<<k<<endl;
    21     int ka=a,kb=b;
    22     a/=g,b/=g;k/=g;
    23     //cout<<"a=="<<a<<" b=="<<b<<" k=="<<k<<endl;
    24     int res=0x7fffffffffffffff;
    25     int tmpx=x%b,tmpy=(k-a*tmpx)/b;
    26     res=min(res,abs(tmpx)+abs(tmpy));
    27     //cout<<"tmpx=="<<tmpx<<" tmpy=="<<tmpy<<" res=="<<res<<endl;
    28     if(tmpx==0){
    29         res=min(res,abs(tmpx+b)+abs(tmpy-a));
    30         res=min(res,abs(tmpx-b)+abs(tmpy+a));
    31     }
    32     
    33     else if(tmpx<0) tmpx+=b,tmpy-=a,res=min(res,abs(tmpx)+abs(tmpy));
    34     else tmpx-=b,tmpy+=a,res=min(res,abs(tmpx)+abs(tmpy));
    35     //cout<<"tmpx=="<<tmpx<<" tmpy=="<<tmpy<<" res=="<<res<<endl;
    36     tmpy=y%a,tmpx=(k-b*tmpy)/a;
    37     res=min(res,abs(tmpx)+abs(tmpy));
    38     //cout<<"tmpx=="<<tmpx<<" tmpy=="<<tmpy<<" res=="<<res<<endl;
    39     if(tmpy==0){
    40         res=min(res,abs(tmpx+b)+abs(tmpy-a));
    41         res=min(res,abs(tmpx-b)+abs(tmpy+a));
    42     }
    43     else if(tmpy<0) tmpy+=a,tmpx-=b,res=min(res,abs(tmpx)+abs(tmpy));
    44     else tmpy-=a,tmpx+=b,res=min(res,abs(tmpx)+abs(tmpy));
    45     //cout<<"tmpx=="<<tmpx<<" tmpy=="<<tmpy<<" res=="<<res<<endl;
    46     return res;
    47 }
    48 int k[N];
    49  main(){
    50     //freopen("1.in","r",stdin);
    51     int n,a,b;
    52     scanf("%lld%lld%lld",&n,&a,&b);
    53     for(int i=1;i<=n;++i) scanf("%lld",&k[i]);
    54     int flag=0;
    55     long long ans=0;
    56     int x,y;
    57     int g;
    58     exgcd(a,b,x,y,g);
    59     int tmpx=x,tmpy=y;
    60     for(int i=1;i<=n;++i){    
    61         //cout<<"x=="<< x<<" y=="<<y<<endl;
    62         //cout<<"gcd=="<<g<<" k[i]=="<<k[i]<<endl;
    63         if(k[i]%g!=0) {flag=1;break;}
    64         int tmp=k[i]/g;
    65         x=tmpx*tmp,y=tmpy*tmp;
    66         //cout<<"x=="<<x<<" y=="<<y<<endl;
    67         int res=solve(a,b,x,y,k[i],g);
    68         //cout<<"res=="<<res<<endl;
    69         ans+=res;
    70     }
    71     if(flag) puts("-1");
    72     else printf("%lld
    ",ans);
    73     return 0;
    74 }
    array

    T2 pair

    考场上一看到这题发现和队长快跑那题很像,然后就回忆起了那天调了一个下午影魔的一个log在线做法然后水果那道题的惨痛经历,果然水题没有好下场啊qwq

    首先设出dp定义$dp_{i,s}$表示到i并且选i,$max(a_i)=j$的最大值。

    我们在来考虑他给出的限制,如果$a_i < b_j$且 $a_j>b_i$ 那么一定是i在j前。反之同理。

    那么我们可以按$max(a,b)$排序,然后dp

    转移时,我们要分类讨论

    如果$a_i < b_i$,因为要$max(a)<b_i$所以,$f[i-1][a[i]]$到$f[i-1][b[i]]$的最大值不会改变,直接加$val$就好,在$1-a[i-1]$的最大值变为了$a[i]$,用前面的最大值更新dp就好了。

    如果$a_i > b_i$,因为要$max(a)<b_i$所以,$1-b[i]$的最大值变为$a[i]$,同上更新即可。

    以上操作只需要维护一棵资磁区间加,单点修改,区间max线段树就好了。

      1 #include<bits/stdc++.h>
      2 #define int long long
      3 using namespace std;
      4 const int N=2e5+10;
      5 int cnt,lsh[N<<1];
      6 struct node{
      7     int a,b,w;
      8 }p[N];
      9 int dp[N];
     10 bool cmp(node x,node y)
     11 {
     12     if(max(x.b,x.a)!=max(y.b,y.a))
     13         return max(x.b,x.a)<max(y.b,y.a);
     14     else return x.b<y.b;
     15 }
     16 struct SegmentTree{
     17     int l,r,mx,lazy;
     18 }tr[N<<2];
     19 void build(int p,int l,int r){
     20     tr[p].l=l,tr[p].r=r;
     21     if(l==r){return ;}
     22     int mid=(l+r)>>1;
     23     build(p<<1,l,mid);
     24     build(p<<1|1,mid+1,r);
     25 }
     26 void down(int p){
     27     if(!tr[p].lazy) return ;
     28     tr[p<<1].lazy+=tr[p].lazy,tr[p<<1|1].lazy+=tr[p].lazy;
     29     tr[p<<1].mx+=tr[p].lazy,tr[p<<1|1].mx+=tr[p].lazy;
     30     tr[p].lazy=0;
     31 }
     32 void add(int p,int l,int r,int ll,int rr,int val){
     33     if(ll<=l&&r<=rr){
     34         tr[p].mx+=val;
     35         tr[p].lazy+=val;
     36         return ;
     37     }
     38     down(p);
     39     int mid=(tr[p].l+tr[p].r)>>1;
     40     if(ll<=mid) add(p<<1,l,mid,ll,rr,val);
     41     if(rr>mid) add(p<<1|1,mid+1,r,ll,rr,val);
     42     tr[p].mx=max(tr[p<<1].mx,tr[p<<1|1].mx);
     43 }
     44 int q_mx=0;
     45 void ask(int p,int l,int r,int ll,int rr){
     46     if(ll<=l&&r<=rr){
     47         q_mx=max(q_mx,tr[p].mx);
     48         return ;
     49     }
     50     down(p);
     51     int mid=(tr[p].l+tr[p].r)>>1;
     52     if(ll<=mid) ask(p<<1,l,mid,ll,rr);
     53     if(rr>mid) ask(p<<1|1,mid+1,r,ll,rr);
     54 }
     55 void update(int p,int l,int r,int pos,int val){
     56     if(l==r){
     57         tr[p].mx=max(val,tr[p].mx);
     58         return ;
     59     }
     60     down(p);
     61     int mid=(tr[p].l+tr[p].r)>>1;
     62     if(pos<=mid) update(p<<1,l,mid,pos,val);
     63     else update(p<<1|1,mid+1,r,pos,val);
     64     tr[p].mx=max(tr[p<<1].mx,tr[p<<1|1].mx);
     65 }
     66 signed main(){
     67 //    freopen("2.in","r",stdin);
     68     int n;
     69     scanf("%lld",&n);
     70     for(int i=1;i<=n;++i){
     71         scanf("%lld%lld%lld",&p[i].a,&p[i].b,&p[i].w);
     72     }
     73     sort(p+1,p+n+1,cmp);
     74     for(int i=1;i<=n;++i) lsh[++cnt]=p[i].a,lsh[++cnt]=p[i].b;
     75     sort(lsh+1,lsh+cnt+1);
     76     int len=unique(lsh+1,lsh+cnt+1)-(lsh+1);
     77     int maxn=0;
     78     for(int i=1;i<=n;++i){
     79         p[i].a=lower_bound(lsh+1,lsh+len+1,p[i].a)-lsh;
     80         p[i].b=lower_bound(lsh+1,lsh+len+1,p[i].b)-lsh;
     81         maxn=max(maxn,p[i].a);
     82         maxn=max(maxn,p[i].b);
     83     }
     84     build(1,1,maxn);
     85 //    cout<<"maxn=="<<maxn<<endl;
     86     for(int i=1;i<=n;++i){
     87         if(p[i].a>p[i].b){
     88             q_mx=0;
     89             ask(1,1,maxn,1,p[i].b);
     90 //            cout<<q_mx<<endl;
     91             dp[i]=max(dp[i],q_mx+p[i].w);
     92         }
     93         else{
     94             q_mx=0;
     95             ask(1,1,maxn,1,p[i].a);
     96 //            cout<<q_mx<<endl;
     97             dp[i]=max(dp[i],q_mx+p[i].w);
     98             add(1,1,maxn,p[i].a,p[i].b,p[i].w);
     99         }
    100         update(1,1,maxn,p[i].a,dp[i]);
    101     }
    102     printf("%lld
    ",tr[1].mx);
    103 }
    pair

    T3 distance

    感觉思路和meet in the middle 有些相似,不过也不太一样废话,这提重点思路就在于相当于从中间把两条路径连起来。

    具体做法就是以所有特殊点为源点,跑一个多源点spfa,然后记录每个点,离最特殊点的距离,以及是那一个特殊点。跑完spfa后枚举所有边,如果两个端点不同就更新这两个端点的最近特殊点的答案。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define int long long
     4 const int N=2e5+10;
     5 int to[N<<1],nex[N<<1],edge[N<<1],fr[N<<1];
     6 int first[N];
     7 bool is[N];
     8 int sp[N],dis[N],v[N],ans[N];
     9 int tot;
    10 void add(int a,int b,int c){
    11     to[++tot]=b,nex[tot]=first[a],first[a]=tot,edge[tot]=c,fr[tot]=a;
    12 }
    13 int sour[N];
    14 int n,m,p;
    15 void spfa(){
    16     for(int i=1;i<=n;++i) dis[i]=10000000000000000;
    17     queue<int> q;
    18     for(int i=1;i<=p;++i) q.push(sp[i]),dis[sp[i]]=0,v[sp[i]]=1,sour[sp[i]]=sp[i];
    19     while(q.size()){
    20         int x=q.front();q.pop();
    21         v[x]=0;
    22         for(int i=first[x];i;i=nex[i]){
    23             int y=to[i],z=edge[i];
    24             if(dis[y]>dis[x]+z){
    25                 dis[y]=dis[x]+z;
    26                 sour[y]=sour[x];
    27                 if(!v[y]) q.push(y),v[y]=1;
    28             }
    29         }
    30     }
    31 }
    32 signed main(){
    33     //freopen("3.in","r",stdin);
    34     scanf("%lld%lld%lld",&n,&m,&p);
    35     for(int i=1;i<=n;++i) ans[i]=10000000000000000;
    36     for(int i=1;i<=p;++i) {scanf("%lld",&sp[i]);is[sp[i]]=1;}
    37     for(int i=1;i<=m;++i){
    38         int x,y,w;
    39         scanf("%lld%lld%lld",&x,&y,&w);
    40         add(x,y,w);
    41         add(y,x,w);
    42     }
    43     spfa();
    44 //    for(int i=1;i<=n;++i) cout<<"sour["<<i<<"]=="<<sour[i]<<" dis["<<i<<"]=="<<dis[i]<<endl;
    45     for(int i=1;i<=tot;i+=2){
    46         if(sour[fr[i]]!=sour[to[i]]){
    47 //            cout<<"g"<<fr[i]<<" "<<to[i]<<" "<<edge[i]<<endl;
    48             ans[sour[fr[i]]]=min(ans[sour[fr[i]]],dis[fr[i]]+dis[to[i]]+edge[i]);
    49             ans[sour[to[i]]]=min(ans[sour[to[i]]],dis[fr[i]]+dis[to[i]]+edge[i]);
    50 
    51         }
    52     }
    53     for(int i=1;i<=p;++i) printf("%lld ",ans[sp[i]]);
    54 }
    55 /*
    56 5 6 3
    57 2 4 5
    58 1 2 4
    59 1 3 1
    60 1 4 1
    61 1 5 4
    62 2 3 1
    63 3 4 3
    64 */
    distance
  • 相关阅读:
    Apache 配置多个HTTPS站点(转载)
    一个显示某段时间内每个月的方法 返回由这些月 (转载)
    支付宝支付出现 openssl_sign(): supplied key param cannot be coerced into a private key
    tp5 setInc 中一直返回 0
    数据库 SQLSTATE[22003]: Numeric value out of range: 1264 Out of range value for col
    MYSQL设置查询内存表大小
    PHP原生的mysql查询
    支付宝 APP支付 错误码
    centos6.5中安装完成扩展后 在modules 也能找到 但是在phpinfo中看不见
    configure: error: Cannot find php-config. Please use --with-php-config=PATH
  • 原文地址:https://www.cnblogs.com/leom10/p/11759683.html
Copyright © 2011-2022 走看看