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\n",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\n",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\n",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\n",ans);
    return 0;
}

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

时间: 2024-07-31 14:34:51

Codeforces Round#361(div 2)的相关文章

Codeforces Round #361 (Div. 2) D. Friends and Subsequences RMQ+二分

题目链接 http://codeforces.com/problemset/problem/689/D 代码 1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 using namespace std; 5 6 const int maxn = 200000 + 10; 7 int n, a[maxn], b[maxn]; 8 int d_min[maxn][30]; 9 int d_max[m

Codeforces Round #361 (Div. 2) C D

C 给出一个m 此时有 四个数 分别为x k*x k*k*x k*k*k*x k大于1 x大于等于1 要求求出来一个最小的值n 使其满足 这四个数中的最大值小于n 这四个数可能的组数为m 可以看出这四个数递增 所以最大值必定是第四个 所以我们二分n 需要注意的是longlong可以定义到1e18 初始应当是l小于等于可能的最小值(0) r大于等于可能的最大值(1e18) 如果初始范围就定义错误的话 二分不会出现正确答案 在这里由于控制l=mid+1或者r=mid-1 这一类的时候 容易丢失mid

Codeforces Round #361 (Div. 2) D

D - Friends and Subsequences Description Mike and !Mike are old childhood rivals, they are opposite in everything they do, except programming. Today they have a problem they cannot solve on their own, but together (with you) — who knows? Every one of

Codeforces Round #361 (Div. 2) D.Friends and Subsequences (multiset + 尺取法)

D. Friends and Subsequences Mike and !Mike are old childhood rivals, they are opposite in everything they do, except programming. Today they have a problem they cannot solve on their own, but together (with you) — who knows? Every one of them has an

【CF】Codeforces Round #361 (Div. 2)

难得有想法写一整套题解 首先想说的是,这场CF,我感觉是div2极为不错的一场(对于中档选手<因为我就出了三题,还掉了一个-- 说笑了,感觉这一场很耐人寻味.就是那种抓破头皮想不出,知道做法后细细品味,有种   哦~~~~~这样啊~~~~好神奇!!! 的感觉 首先..秀一下战绩 不多说了 都在题里 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ A. Mike and Cellphone time limit per test 1 second memory limit per test 256 megaby

Codeforces Round #361 (Div. 2) E. Mike and Geometry Problem

题目链接:传送门 题目大意:给你n个区间,求任意k个区间交所包含点的数目之和. 题目思路:将n个区间都离散化掉,然后对于一个覆盖的区间,如果覆盖数cnt>=k,则数目应该加上 区间长度*(cnt与k的组合数) ans=ans+(len*C(cnt,k))%mod; #include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <algorith

Codeforces Round #361 (Div. 2) D - Friends and Subsequences

题目大意:给你两个长度为n的数组a, b,问你有多少个问你有多少个区间满足 a中最大值等于b中最小值. 思路:我本来的想法是用单调栈求出每个点的管辖区间,然后问题就变成了巨麻烦的线段覆盖问题,就爆炸写了 一晚上假算法.正解就是枚举一个端点,然后二分找右端点的区间,因为满足一个很神奇的单调性,然后st表维护 一下区间最值就好了. #include<bits/stdc++.h> #define LL long long #define fi first #define se second #def

Codeforces Round #279 (Div. 2) ABCD

Codeforces Round #279 (Div. 2) 做得我都变绿了! Problems # Name     A Team Olympiad standard input/output 1 s, 256 MB  x2377 B Queue standard input/output 2 s, 256 MB  x1250 C Hacking Cypher standard input/output 1 s, 256 MB  x740 D Chocolate standard input/

Codeforces Round #428 (Div. 2)

Codeforces Round #428 (Div. 2) A    看懂题目意思就知道做了 #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a; i<=b; ++i) #define per(i,b,a) for (int i=b; i>=a; --i