codeforces #535 div 2

暂时做了4题,先放一下有时间做最后一题(当然如果我真的能做出的话。。。)

A题:

英文单词别拼错就没什么问题吧

#include <cstdio>
#include <cstring>

using namespace std;

char str[10][10] = {"" , "" , "twenty" , "thirty" , "forty" , "fifty" , "sixty" , "seventy" ,"eighty" , "ninety"};
char single[10][10] = {"zero" , "one","two","three","four","five","six","seven","eight","nine"};
char dou[10][10] = {"ten" ,"eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen","eighteen","nineteen"};
int main()
{
    int x;
    while(~scanf("%d" , &x)){
        if(x<10){
            printf("%s\n" , single[x]);
        }
        else if(x<20){
            printf("%s\n" , dou[x%10]);
        }
        else{
            int tmp = x%10;
            printf("%s" , str[x/10]);
            if(tmp){
                printf("-%s" , single[tmp]);
            }
            printf("\n");
        }
    }
    return 0;
}

B题:
给定一个1~n的范围,问这个范围内只包含4或者7的数字有多少个

假设n是一个长度为l的整数,那么肯定所有 <l 长度的整数包含4,7的都能取到

就是(2^1+2^2+...2^(l-1))

那么就要确定 l 位整数的情况,不断从前往后按照那时的位置上的数字进行判断

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int dig[15];

int qpow(int digit)
{
    int a=2 , b=digit , ans=1;
    while(b)
    {
        if(b&1) ans*=a;
        a*=a;
        b>>=1;
    }
    return ans;
}

int getDigit(int x)
{
    int ans=0;
    while(x){
        x/=10;
        ans++;
    }
    return ans;
}

void getHead(int x , int len)
{
    int  index=len;
    while(x){
        dig[index--]=x%10;
        x/=10;
    }
}

int main()
{
    int n;
    while(~scanf("%d" , &n))
    {
        int len = getDigit(n);
        int ans=0;
        for(int i=1 ; i<=len-1 ; i++)
            ans+= qpow(i);
        if(ans == 1) ans-=1;
        getHead(n , len);
        for(int i=1 ; i<=len ; i++){
             //   cout<<dig[i]<<endl;
            if(dig[i]>7){
                ans += qpow(len-i+1);
                break;
            }
            else if(dig[i] == 7){
                ans += qpow(len-i);
                if(i == len) ans+=1;
            }
            else if(dig[i]>4){
                ans += qpow(len-i);
                break;
            }
            else if(dig[i]==4){
                if(i == len) ans+=1;
                continue;
            }
            else break;
        }
        printf("%d\n" , ans);
    }
    return 0;
}

C题:

一个二分题,当且仅当t在,第一个数时输出-1 , 否则二分判断 t>=最大数,且所有数之和<=t*m即可,这个略微想一下就好了,注意乘法溢出,我在这一直wa

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
#define N 1000005
int l,t,m;
int a , b , n;
#define ll long long

bool check(int mid)
{
    ll cnt = mid-l+1;
    ll st = a+(ll)(l-1)*b , la=(ll)(mid-1)*b+a;
    if(t>=la && (st+la)*cnt/2<=(ll)t*m) return true;
    else return false;
}

int bin_search()
{
    if(a+(ll)(l-1)*b > (ll)t) return -1;
    int left = l , right = N , ans = l;
    while(left<=right)
    {
        int mid = left+(right-left)/2;
        if(check(mid)){
            left = mid+1;
            ans = mid;
        }else right=mid-1;
    }
    return ans;
}

int main()
{
   // freopen("a.in" , "r" , stdin);

    while(~scanf("%d%d%d" , &a , &b , &n))
    {
        for(int i=1 ; i<=n ; i++){
            scanf("%d%d%d" , &l , &t , &m);
            printf("%d\n" , bin_search());
        }
    }
    return 0;
}

D题:

后缀数组题,这里虽然一看就想到暴力,但是看一下时间复杂度就呵呵了

利用后缀数组判断当前位置插入一个新的p , 覆盖前一个p的时候是否有冲突即可

当前位置 cur , 其实就是判断cur的后缀是不是 0 开头的子串

然后就用vis[]保存插在当前点是否影响即可

然后i=1~m按顺序查询,单位时间内就解决了

这里各种特殊情况要考虑,我太欠缺考虑了,完全是依赖cf上可以错了看数据慢慢改对的。。。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
#define N 1000005
#define ll long long
const int MOD = 1e9+7;

char str[N];
int a[N] , n , m;
int r[N] , sa[N] , height[N] , rank[N] , wa[N] , wb[N] , wsf[N] , wv[N];
bool vis[N];

int cmp(int *r , int a , int b , int l)
{
    return r[a]==r[b] && r[a+l]==r[b+l];
}

void get_sa(int *r , int *sa , int n , int m)
{
    int *x=wa , *y=wb , *t;
    int i,j,p;
    for(i=0 ; i<m ; i++) wsf[i]=0;
    for(i=0 ; i<n ; i++) wsf[x[i]=r[i]]++;
    for(i=1 ; i<m ; i++) wsf[i]+=wsf[i-1];
    for(i=n-1 ; i>=0 ; i--) sa[--wsf[x[i]]]=i;

    p=1 ;
    for(j=1 ; p<n ; j*=2 , m=p){
        for(p=0 , i=n-j ; i<n ; i++) y[p++] = i;
        for(i=0 ; i<n ; i++) if(sa[i]>=j) y[p++]=sa[i]-j;

        for(i=0 ; i<n ; i++) wv[i]=x[y[i]];
        for(i=0 ; i<m ; i++) wsf[i]=0;
        for(i=0 ; i<n ; i++) wsf[wv[i]]++;
        for(i=1 ; i<m ; i++) wsf[i]+=wsf[i-1];
        for(i=n-1 ; i>=0 ; i--) sa[--wsf[wv[i]]]=y[i];

        t=x , x=y , y=t;
        x[sa[0]]=0;
        for(p=1 , i=1 ; i<n ; i++)
            x[sa[i]] = cmp(y , sa[i-1] , sa[i] , j)?p-1:p++;
    }
}

void callHeight(int *r , int *sa , int n , int m)
{
    int i , j , k=0;
    for(i=1 ; i<=n ; i++) rank[sa[i]]=i;
    for(i=0 ; i<n ; height[rank[i++]]=k)
        for(k?k--:0 , j=sa[rank[i]-1] ; r[i+k] == r[j+k] ; k++) ;
    return;
}

void biaoji(int n)
{
    memset(vis , 0 , sizeof(vis));
    vis[0]=true;
    int order = 0; //记录以开头为起点的排名
    for(int i=1 ; i<=n ; i++){
        if(sa[i] == 0) order = i;
    }
    int len=N;
    for(int i=order ; i>=1 ; i--){
        int pos = sa[i-1];
        len = min(len , height[i]);
        if(pos+len>=n) vis[pos]=true;
    }
    len=N;
    for(int i=order+1 ; i<=n ; i++){
        int pos = sa[i];
        len = min(len , height[i]);
        if(pos+len>=n) vis[pos]=true;
    }
}

int qpow(int cnt)
{
    if(!cnt) return 0;
    ll ans = 1 , a = 26 ;
    while(cnt)
    {
        if(cnt&1) ans = (ans*a)%MOD;
        a = (a*a)%MOD;
        cnt>>=1;
    }
    return (int)ans;
}

int main()
{
   // freopen("a.in" , "r" , stdin);

    while(~scanf("%d%d" , &n , &m))
    {
        scanf("%s" , str);
        for(int i=0 ; i<m ; i++) scanf("%d" , a+i);
        sort(a , a+m);

        int len = strlen(str);
        for(int i=0 ; i<len ; i++){
            r[i] = (int)str[i];
        }
        r[len]=0;
        get_sa(r , sa , len+1 , 128);
        callHeight(r , sa , len , 128);
        biaoji(len);

        int cnt = a[0]-1;
        bool flag = true;
        for(int i=1 ; i<m ; i++){
            int dis = a[i]-a[i-1];
            if(dis>=len){
                cnt+=dis-len;
            }else{
                if(!vis[dis]) {
                  //  cout<<i<<" "<<dis<<endl;
                    flag = false;
                    break;
                }
            }
        }
        cnt+=n+1-a[m-1]-len;
        int ans;
        if(!flag){
         //   cout<<"exist "<<endl;
            ans = 0;

        }
        else if(m == 0){
            ans = qpow(n);
        }
        else{
               // cout<<"no "<<endl;
            if(cnt)
                ans = qpow(cnt);
            else ans=1;
        }
        printf("%d\n" , ans);
    }
    return 0;
}

时间: 2024-08-06 11:38:52

codeforces #535 div 2的相关文章

Codeforces Round #535 (Div. 3)小上分记

Codeforces Round #535 (Div. 3)小上分记 前言 被拉去买新年衣服了,导致半小时后才进场. 虽然做了4道题,但是rating还是涨得不多. 用predictor看了rating变化后心灰意冷,不看E题了. A ...800的难度. B 本来还在想要不要用什么STL.后来发现直接用桶就行了.然后就可以水过了. C 题意差点理解不了. 就6种情况都去考虑一下,找最小代价的即可.不要考虑少了. 每次都是\(O(n)\)的,所以能搞. D 贪心地换字母即可. E 坑.待填. 原

B类-Codeforces Round #535 (Div. 3)C. Nice Garland

Codeforces Round #535 (Div. 3)C. Nice Garland 题意: 由'R', 'G' and 'B' 三个字母组成的一个字符串,每两个相同的字母需要相差3,找出最小需要交换次数. 分析: 这个字符串的长度大于等于3的时候,一定是RBG这三个字符的某一个排列的循环.RBG一共最多有6种排列方式{"RGB","RBG","BGR","BRG","GRB","GBR&q

Codeforces Round #535 (Div. 3) 题解

Codeforces Round #535 (Div. 3) 题目总链接:https://codeforces.com/contest/1108 太懒了啊~好久之前的我现在才更新,赶紧补上吧,不能漏掉了. A. Two distinct points 题意: 给出两个区间的左右边界,输出两个数,满足两个数分别在两个区间内且这两个数不相等. 题解: 直接输出左端点然后判断一下就行了. 代码如下: #include <bits/stdc++.h> using namespace std; type

Codeforces #258 Div.2 E Devu and Flowers

大致题意: 从n个盒子里面取出s多花,每个盒子里面的花都相同,并且每个盒子里面花的多数为f[i],求取法总数. 解题思路: 我们知道如果n个盒子里面花的数量无限,那么取法总数为:C(s+n-1, n-1) = C(s+n-1, s). 可以将问题抽象成:x1+x2+...+xn = s, 其中0<=xi <= f[i],求满足条件的解的个数. 两种方法可以解决这个问题: 方法一:这个问题的解可以等价于:mul = (1+x+x^2+...+x^f[1])*(1+x+x^2+...+x^f[2]

Codeforces #259 Div.2

A. Little Pony and Crystal Mine 模拟题. 用矩阵直接构造或者直接根据关系输出 B. Little Pony and Sort by Shift 模拟题. 通过提供的操作得到的序列只能是两段递增或者整个序列递增. 那么可以求得第一段递增序列长度为0-p 如果整个序列是递增,即 p= n-1 那么操作次数就是0. 否则,假设是两段递增,把原始的序列恢复出来,设当前序列是AB,那么A就是0-p BA = (A'B')', '表示对序列进行翻转, 如果BA是有序的,那么需

Codeforces #250 (Div. 2) C.The Child and Toy

之前一直想着建图...遍历 可是推例子都不正确 后来看数据好像看出了点规律 就抱着试一试的心态水了一下 就....过了..... 后来想想我的思路还是对的 先抽象当前仅仅有两个点相连 想要拆分耗费最小,肯定拆相应权值较小的 在这个基础上考虑问题就能够了 代码例如以下: #include <cstdio> #include <iostream> #include <algorithm> #define MAXN 10010 #define ll long long usi

Codeforces #256 Div.2

B. Suffix Structure 1. 先判断s去掉一些元素是否能构成t,如果可以就是automaton 判断的方法也很简单,two pointer,相同元素同时++,不相同s的指针++,如果t能全找到,那么s能够去掉元素构成t. bool f(string s, string t) { int i = 0, j = 0; while (i < s.size() && j < t.size()) { if (s[i] == t[j]) { i++; j++; } else

Codeforces Round #535 (Div. 3) F

F. MST Unification 题目传送门 题意: 给你n个顶点,m条边:保证没有重边,其中存在多个MST(最小生成树), 你可以修改一些边的权值,让其中有且仅有一个最小生成树,求最少操作的边数. 思路: 最小生成树算法的加工,我们从kruskal算法入手,kruskal就是先对边排序, 然后遍历边不断加入一些合格边来完善最小生成树 那么在这个过程中,如果边的权值一样的话,就会产生多种MST,但是这里 不能仅仅只是累计相同权值的边数,因为与合格边相同权值的边可能可以选择 多条. 所以我们可

Codeforces Round #535 (Div. 3) 1108C - Nice Garland

#include <bits/stdc++.h> using namespace std; int main() { #ifdef _DEBUG freopen("input.txt", "r", stdin); // freopen("output.txt", "w", stdout); #endif int n; string s; cin >> n >> s; vector<in