zoukankan      html  css  js  c++  java
  • USACO18FEB Platinum

    SlingShot 求数轴上从x到y的最短路( 边长为1),有若干个从xi到yi长度为ti的传送门,每次只能选择其中一个使用。

    即求min(|x-y|,min{|a-x|+|b-y|+c}),拆开绝对值,根据相对位置分开讨论,转换成二维数点问题。

    MLE的主席树版本:

     1 #include<bits/stdc++.h>
     2 #define P pair<ll,ll>
     3 #define fir first
     4 #define sec second
     5 using namespace std;
     6 typedef long long ll;
     7 int read()
     8 {
     9     int x=0;char ch=getchar();
    10     while (ch<'0'||ch>'9') ch=getchar();
    11     while ('0'<=ch&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    12     return x;
    13 }
    14 const int N=1e9,T=6e6,M=1e5+5;
    15 const ll inf=1ll<<60;
    16 P Min[T];
    17 int ls[T],rs[T],A[M],x,y,sc,n,rt0[M],rt1[M],m;
    18 struct node{ll a,b,c;}p[M];
    19 bool cmp(const node &A,const node &B) {return A.a<B.a;}
    20 P fmin(P a,P b){
    21     return P(min(a.fir,b.fir),min(a.sec,b.sec));
    22 };
    23 void ins(int &k,int pk,int l,int r,int x,P y)
    24 {
    25     k=++sc;ls[k]=ls[pk];rs[k]=rs[pk];Min[k]=Min[pk];
    26     if (l==r) {Min[k]=fmin(Min[k],y);return;}
    27     int mid=(l+r)>>1;
    28     if (x<=mid) ins(ls[k],ls[pk],l,mid,x,y);
    29     else ins(rs[k],rs[pk],mid+1,r,x,y);
    30     Min[k]=fmin(Min[ls[k]],Min[rs[k]]);
    31 }
    32 P qry(int k,int l,int r,int L,int R)
    33 {
    34     if (!k) return P(inf,inf);
    35     if (L<=l&&r<=R) return Min[k];
    36     int mid=(l+r)>>1;P mn=P(inf,inf);
    37     if (L<=mid) mn=fmin(mn,qry(ls[k],l,mid,L,R));
    38     if (R>mid) mn=fmin(mn,qry(rs[k],mid+1,r,L,R));
    39     return mn;
    40 }
    41 int main()
    42 {
    43     n=read();m=read();Min[0]=P(inf,inf);
    44     for (int i=1;i<=n;i++)
    45       p[i].a=read(),p[i].b=read(),p[i].c=read(),A[i]=p[i].a;
    46     sort(p+1,p+n+1,cmp);
    47     sort(A+1,A+n+1);//寻址数组 
    48     for (int i=n;i>=1;i--)
    49         ins(rt0[i],rt0[i+1],0,N,p[i].b,P(p[i].a-p[i].b+p[i].c,p[i].a+p[i].b+p[i].c));
    50     for (int i=1;i<=n;i++)
    51         ins(rt1[i],rt1[i-1],0,N,p[i].b,P(-p[i].a-p[i].b+p[i].c,-p[i].a+p[i].b+p[i].c));
    52     while (m--)
    53     {
    54         x=read();y=read();
    55         ll ans=abs(x-y);
    56         int k=upper_bound(A+1,A+n+1,x)-A-1; 
    57         ans=min(ans,qry(rt0[k+1],1,N,1,y).fir-x+y);
    58         ans=min(ans,qry(rt1[k],1,N,1,y).fir+x+y);
    59         ans=min(ans,qry(rt0[k+1],1,N,y,N).sec-x-y);
    60         ans=min(ans,qry(rt1[k],1,N,y,N).sec+x-y);
    61         printf("%lld
    ",ans);
    62     }
    63     return 0;
    64 }

    正常二维数点的树状数组版本(AC):

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 int read()
     5 {
     6     int x=0;char ch=getchar();
     7     while (ch<'0'||ch>'9') ch=getchar();
     8     while ('0'<=ch&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
     9     return x;
    10 }
    11 const int M=1e5+5;
    12 const ll inf=1ll<<60;
    13 int A[M],n,m,tot,t,B[M*2]; ll ans[M],bit[M*2];
    14 vector<int> vec1[M],vec2[M];
    15 struct node{ll a,b,c,d;}p[M],q[M];
    16 bool cmp(const node &A,const node &B) {return A.a<B.a;}
    17 int lowbit(int x) {return x&(-x);}
    18 void add1(int x,ll y){while (x<=tot) bit[x]=min(bit[x],y),x+=lowbit(x);}//前缀最小值 
    19 ll qry1(int x){ll res=inf;while (x) res=min(res,bit[x]),x-=lowbit(x);return res;}
    20 void add2(int x,ll y){while (x) bit[x]=min(bit[x],y),x-=lowbit(x);}//后缀最小值 
    21 ll qry2(int x){ll res=inf;while (x<=tot) res=min(res,bit[x]),x+=lowbit(x);return res;}
    22 void init(){for (int i=1;i<=tot;i++) bit[i]=inf;}
    23 int main()
    24 {
    25     n=read();m=read();
    26     for (int i=1;i<=n;i++)
    27       p[i].a=read(),p[i].b=B[++tot]=read(),p[i].c=read(),A[i]=p[i].a;
    28     sort(p+1,p+n+1,cmp);sort(A+1,A+n+1);//寻址数组 
    29     for (int i=1;i<=m;i++) 
    30     {
    31         q[i].a=read(),q[i].b=B[++tot]=read();ans[i]=abs(q[i].a-q[i].b);
    32         int k=upper_bound(A+1,A+n+1,q[i].a)-A-1; 
    33         vec1[k+1].push_back(i);
    34         vec2[k].push_back(i);
    35     }
    36     sort(B+1,B+tot+1);tot=unique(B+1,B+tot+1)-B-1;
    37     for (int i=1;i<=n;i++) p[i].d=lower_bound(B+1,B+tot+1,p[i].b)-B;
    38     for (int i=1;i<=m;i++) q[i].d=lower_bound(B+1,B+tot+1,q[i].b)-B;
    39     init();
    40     for (int i=n;i>=1;i--)
    41     {
    42         add1(p[i].d,p[i].a-p[i].b+p[i].c);
    43         for (int j=0;j<vec1[i].size();j++)
    44           t=vec1[i][j],ans[t]=min(ans[t],qry1(q[t].d)-q[t].a+q[t].b);
    45     }
    46     init();
    47     for (int i=n;i>=1;i--)
    48     {
    49         add2(p[i].d,p[i].a+p[i].b+p[i].c);
    50         for (int j=0;j<vec1[i].size();j++)
    51           t=vec1[i][j],ans[t]=min(ans[t],qry2(q[t].d)-q[t].a-q[t].b);
    52     }
    53     init();
    54     for (int i=1;i<=n;i++)
    55     {
    56         add1(p[i].d,-p[i].a-p[i].b+p[i].c);
    57         for (int j=0;j<vec2[i].size();j++)
    58           t=vec2[i][j],ans[t]=min(ans[t],qry1(q[t].d)+q[t].a+q[t].b);
    59     }
    60     init();
    61     for (int i=1;i<=n;i++)
    62     {
    63         add2(p[i].d,-p[i].a+p[i].b+p[i].c);
    64         for (int j=0;j<vec2[i].size();j++)
    65           t=vec2[i][j],ans[t]=min(ans[t],qry2(q[t].d)+q[t].a-q[t].b);
    66     }
    67     for (int i=1;i<=m;i++) printf("%lld
    ",ans[i]);
    68     return 0;
    69 }

    Newbarn 加点x,询问x在树上能走的最远距离

    最远距离一定会走到直径端点。维护每棵树的直径(维护一条就够了)。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int N=100005;
     4 int q,x,dep[N],fa[N][25],id,bel[N],sc,Max,u[N],v[N],tmp;
     5 char s[5];
     6 int lca(int x,int y)
     7 {
     8     if (dep[x]<dep[y]) swap(x,y);
     9     int del=dep[x]-dep[y];
    10     for (int i=20;i>=0;i--)
    11       if (del&(1<<i)) x=fa[x][i];
    12     if (x==y) return x;
    13     for (int i=20;i>=0;i--)
    14       if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
    15     return fa[x][0];
    16 }
    17 int dis(int x,int y) {return dep[x]+dep[y]-2*dep[lca(x,y)];}
    18 int main()
    19 {
    20     scanf("%d",&q);
    21     while (q--)
    22     {
    23         scanf("%s%d",s,&x);
    24         if (s[0]=='B')
    25         {
    26             id++;
    27             if (x!=-1) 
    28             {
    29                 dep[id]=dep[x]+1,fa[id][0]=x; bel[id]=bel[x];
    30                 for (int j=1;j<=20;j++)
    31                   fa[id][j]=fa[fa[id][j-1]][j-1];
    32                 Max=dis(u[bel[id]],v[bel[id]]);
    33                 if (tmp=dis(id,u[bel[id]]),tmp>Max) Max=tmp,v[bel[id]]=id;
    34                 if (tmp=dis(id,v[bel[id]]),tmp>Max) Max=tmp,u[bel[id]]=id;
    35             }else bel[id]=++sc,u[sc]=v[sc]=id;
    36         }else printf("%d
    ",max(dis(x,u[bel[x]]),dis(x,v[bel[x]])));
    37     }
    38     return 0;
    39 }

    Cow Gymnasts 求有多少个数组A任意位i都满足A[i]=sigma[A[i-j+1]>=j](i-j+1<=0时从N开始往下)?(1<=A[i]<=N)

    关键点在发现循环节。大胆从最小位置x入手,设其值为m,则满足y=x(mod gcd(N,m)的位置y的值都为m。

    同样也可以归纳证明,所有位置的值都<=m+1。(注意一个循环节中有一个m+1,那么就不会出现m)

    枚举m,$Ans=sum_{m=1}^{n-1}(2^{gcd(n,m)}-1)+1$。m=n的情况只有可能全是m,故加1。

    把gcd提出来,$Ans=sum_{d|n}2^d*varphi(N/d)-N+2-2^N$。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int mod=1e9+7;
     5 #define P pair<ll,int>
     6 ll n,ans,sum;
     7 map<ll,ll> Phi;
     8 vector<P> vec;
     9 ll ksm(ll x,ll y) {
    10     ll res=1;
    11     while (y) {if (y&1) res=res*x%mod; x=x*x%mod;y>>=1;}
    12     return res;
    13 }
    14 void dvd(ll x)
    15 {
    16     for (int i=2;i<=sqrt(x);i++)
    17       if (x%i==0)
    18       {
    19           sum*=i-1;int cnt=1;x/=i;
    20           while (x%i==0) x/=i,cnt++,sum*=i;
    21           vec.push_back(P(i,cnt));
    22       }
    23     if (x!=1) vec.push_back(P(x,1));
    24 }
    25 void dfs(ll x,int d,ll phi)
    26 {
    27     if (d==vec.size()) {Phi[x]=phi;return;}
    28     dfs(x,d+1,phi);
    29     ll t=vec[d].first,sum=t-1;
    30     for (int i=1;i<=vec[d].second;i++)
    31     {
    32         x*=t;
    33         dfs(x,d+1,phi*sum);
    34         sum*=t;
    35     }
    36 }
    37 int main()
    38 {
    39     scanf("%lld",&n);
    40     if (n==1) return puts("1"),0;
    41     sum=1;dvd(n);
    42     dfs(1,0,1);ans=((2-n-ksm(2,n))%mod+mod)%mod;
    43     for (int i=1;i<=sqrt(n);i++)
    44       if (n%i==0){
    45           ans+=ksm(2,i)*Phi[n/i]%mod; ans%=mod;
    46           if ((ll)i*i!=n) ans+=ksm(2,n/i)*Phi[i]%mod,ans%=mod;
    47       }
    48     printf("%lld
    ",ans);
    49     return 0;
    50 }
  • 相关阅读:
    .Net Core部署到CentOS
    Docker容器中开始.Net Core之路
    自我总结和学习表单提交的几种方式 (二)
    自我总结和学习表单提交的几种方式 (一)
    Asp.Net MVC下自定义错误页和展示错误页的几种方式
    .Net下发送邮件遇到问题及解决方案
    Asp.Net MVC CodeFirst模式数据库迁移步骤
    利用微软认知服务实现语音识别功能
    Asp.Net MVC路由生成URL过程
    针对于多线程概念的理解
  • 原文地址:https://www.cnblogs.com/Scx117/p/9123933.html
Copyright © 2011-2022 走看看