• Codeforces Round #361(div 2)


    A题题目意思很简单,问一种拨号的方式(拨号手势)是不是能拨出唯一的号码(例如253就不是唯一的,因为586也是可以的)

    记录电话上每个格子上下左右是否还有格子,一个拨号手势是唯一的当且仅当,所拨号码的所有格子在同一个方向不同时有格子相邻。

    那么直接mark,判断一下即可:

    #include <cstdio>
    using namespace std;
    char s[10000];
    int n,U,D,L,R;
    int main(){
        scanf("%d %s",&n,s);
        for(int i=0;i<n;i++){
            if(s[i]=='0')D=L=R=1;
            if(s[i]=='1'||s[i]=='4'||s[i]=='7')L=1;
            if(s[i]=='3'||s[i]=='6'||s[i]=='9')R=1;
            if(s[i]=='1'||s[i]=='2'||s[i]=='3')U=1;
            if(s[i]=='7'||s[i]=='9')D=1;
        }if(L&&R&&U&&D)puts("YES");
        else puts("NO");
        return 0;
    }
    

    B题的意思是城市之间两两可以互达,耗时为两者编号的差值,同时也有一些捷径,可以用1单位时间的代价从a到b,问从1到每个点的最短耗时。

    嘛,如果想把两两之间路都建出来再跑最短路,就会发现内存不开心了,由于很多路是等价的关系,所以对于两两之间的耗时为编号的差值这个条件,我们只需要建立n-1条边,从i到i+1建立长度为1的边,然后加上捷径,跑一遍最短路就可以出解了。

    #include <cstdio>  
    #include <cstring> 
    #include <queue> 
    #include <utility> 
    using namespace std;  
    const int N=2000100;  
    const int INF=~0U>>2;  
    typedef pair<int,int>seg;  
    priority_queue<seg,vector<seg>,greater<seg> >q;     
    int d[N],head[N],u[N],v[N],w[N],nxt[N],n,m,ed=0,H,x[N],y[N]; 
    bool vis[N];  
    void add(int a,int b,int c){  
        u[++ed]=a,v[ed]=b,w[ed]=c;
        nxt[ed]=head[u[ed]]; head[u[ed]]=ed;     
    }     
    int Dijkstra(int src){  
        memset(vis,0,sizeof(vis));  
        for(int i=0;i<=n+1;i++)d[i]=INF;  
        d[src]=0;  
        q.push(make_pair(d[src],src));  
        while(!q.empty()){  
            seg now=q.top(); q.pop();  
            int x=now.second;  
            if(vis[x])continue; vis[x]=true;  
            for(int e=head[x];e!=-1;e=nxt[e]) 
            if(d[v[e]]>d[x]+w[e]){  
                d[v[e]]=d[x]+w[e];  
                q.push(make_pair(d[v[e]],v[e]));  
            }   
        } 
    }      
    int a[200005],p[200005];
    int main(){
    	scanf("%d",&n);
        memset(head,-1,sizeof(head));
        for(int i=1;i<=n;i++){scanf("%d",a+i);}
        for(int i=1;i<=n;i++){
            add(i,i+1,1);
            add(i,i-1,1);
            if(a[i]!=i)add(i,a[i],1);
        }Dijkstra(1);
        for(int i=1;i<n;i++)printf("%d ",d[i]);
        printf("%d
    ",d[n]);
        return 0;
    }
    

    C题告诉你末项不超过n,且项数为4的等比数列恰好为m个,求n的最小值

    一开始想着打表找规律,看了好几项没什么头绪,于是只能预处理比值的三次方,二分n,计算等比数列的个数来判断。

    #include <cstdio> 
    using namespace std;
    const int N=1000005;
    long long a[N],n;
    int check(long long x){
        long long s=0;
        for(int i=2;a[i]<=x;i++){
    	      s+=x/a[i];
    	      if(s>=n){return 1;}
        }return 0;
    }
    int main(){
        for(long long i=1;i<=1000000;i++)a[i]=i*i*i;
    	  scanf("%lld",&n);
    	  long long l=1,r=1e18;
    	  while(l<r){
    		    long long mid=(l+r)>>1;
    		    if(check(mid))r=mid;
    		    else l=mid+1; 
    	  }long long sum=0;
    	  for(int i=2;a[i]<=l;i++)sum+=l/a[i];
        if(sum!=n)l=-1;
    	  printf("%lld
    ",l);
    	  return 0;
    }

    D题题意很简单,给出a,b两个数组,求区间,使得在该区间内a的最大值和b的最小值相等,求出区间的个数。

    题解:RMQ问题,打出ST表后,分治求出在固定左端点后符合条件区间的右端点的取值范围,范围的长度和就是答案。

    #include <cstdio>  
    #include <cstring>  
    #include <algorithm> 
    using namespace std;  
    const int N=200010;    
    int d[N][30],f[N][30],a[N],lg2[N];   
    int T,n,l,r,q;  
    void rmq_init(int n){  
        for(int i=2;i<=n;i++)lg2[i]=lg2[i/2]+1;
        for(int i=1;i<=n;i++)scanf("%d",&d[i][0]);
        for(int i=1;i<=n;i++)scanf("%d",&f[i][0]);
        for(int j=1;(1<<j)<=n;j++){  
            for(int i=1;i+(1<<j)-1<=n;i++){  
                d[i][j]=max(d[i][j-1],d[i+(1<<(j-1))][j-1]);
                f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
            }  
        }  
    } 
    int rmq_max(int l,int r){int k=lg2[r-l+1];return max(d[l][k],d[r-(1<<k)+1][k]);}
    int rmq_min(int l,int r){int k=lg2[r-l+1];return min(f[l][k],f[r-(1<<k)+1][k]);}
    int main() {
        scanf("%d",&n);
        long long ans=0;
        rmq_init(n);
        for(int i=1;i<=n;i++){
            int l=i,r=n;
            while(l<r){
                int mid=(l+r+1)>>1;
                if(rmq_max(i,mid)>rmq_min(i,mid))r=mid-1;
                else l=mid;
            }if(rmq_max(i,l)!=rmq_min(i,l))continue;
            int ll=i,rr=l;
            while(ll<rr){
                int mid=(ll+rr)>>1;
                if(rmq_max(i,mid)<rmq_min(i,mid))ll=mid+1;
                else rr=mid;
            }ans+=l-ll+1;
        }printf("%lld
    ",ans);
    }

    E题给出了n个区间,求k个不同区间相交得到的区间长度和。

    拆分成左右端点分段计算(方法巧妙,具体实现看代码)

    #include <cstdio>
    #include <vector>
    #include <algorithm>
    #include <iostream> 
    using namespace std;
    typedef long long LL;
    const int N=200005;
    const int mod=1000000007;
    LL f[N],rf[N];
    int l[N],r[N],m,n,k;
    LL inv(int a,int m){return(a==1?1:inv(m%a,m)*(m-m/a)%m);} 
    LL C(int n,int m){if(n<m||m<0)return 0;return f[n]*rf[m]%mod*rf[n-m]%mod;}
    void init(){
        f[0]=1LL;for(int i=1;i<=200000;i++)f[i]=(LL)f[i-1]*i%mod;
    	  rf[200000]=inv(f[200000],mod);
    	  for(int i=200000;i;i--)rf[i-1]=(LL)rf[i]*i%mod;
    }
    int main(){
        init();
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)scanf("%d%d",&l[i],&r[i]);
        vector<pair<int,int> >V; V.clear();
        for(int i=1;i<=n;i++){
            V.push_back(make_pair(l[i]-1,1));
            V.push_back(make_pair(r[i],-1));
        }sort(V.begin(),V.end());
        long long ans=0;
        int cnt=0,pre;
        for(int i=0;i<V.size();i++){
            ans=(ans+C(cnt,k)*(V[i].first-pre))%mod;
            pre=V[i].first;
            cnt+=V[i].second;
        }printf("%lld
    ",ans);
        return 0;
    }

    注意组合数返回0的情况,WA了好多次,谨记谨记。

  • 相关阅读:
    cf914D. Bash and a Tough Math Puzzle(线段树)
    RNQOJ [stupid]愚蠢的矿工(树形依赖背包)
    BZOJ4552: [Tjoi2016&Heoi2016]排序(线段树 二分)
    多项式系数学习笔记
    BZOJ4653: [Noi2016]区间(线段树 双指针)
    洛谷P3372 【模板】线段树 1(树状数组)
    BZOJ3261: 最大异或和(可持久化trie树)
    BZOJ4260: Codechef REBXOR (01Tire树)
    Android 关于显示键盘,布局错乱网上顶的问题
    Java 输入流读取文本文件换行符问题
  • 原文地址:https://www.cnblogs.com/forever97/p/Codeforces361.html
Copyright © 2020-2023  润新知