牛客练习赛33 A,B,C,D,E,F

19 篇文章 0 订阅
3 篇文章 0 订阅

A - tokitsukaze and Counting

[ L , R ] [L,R] [L,R]之间有多少个数能被 x x x整除.
考虑前缀 [ 1 , L ] [1,L] [1,L],一共有 L / x L/x L/x个数字是 x x x的倍数.签到题不多讲…

#include <cstdio>
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        long long L,R,x;
        scanf("%lld%lld%lld",&L,&R,&x);
        printf("%lld\n",(R/x)-((L-1)/x));
    }
}

B - tokitsukaze and RPG

x x x能被最多的 a [ i ] a[i] a[i]整除,且这样的 x x x有多少个.
a [ i ] a[i] a[i]合并,然后对每一个 i i i进行操作,这样合并之后的复杂度是 O ( n l g n ) O(nlgn) O(nlgn)的.

#include <cstdio>
int cnt[1000005];
int res[1000005];
int main(){
    int n,k,a,mx=0;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++){
        scanf("%d",&a);
        cnt[a]++;
        if(mx<a)mx=a;
    }
    for(int i=1;i<=mx;i++){
        if(cnt[i]){
            for(int j=i;j<=k;j+=i)res[j]+=cnt[i];
        }
    }
    int resT=0,t=0;
    for(int i=1;i<=k;i++){
        if(resT<res[i])resT=res[i],t=0;
        if(resT==res[i])t++;
    }
    printf("%d %d\n",resT,t);
}

C - tokitsukaze and Number Game

问将数 X X X重排序以后最大的数,且这个数能被8整除.
根据 8 8 8的性质,任意被8整除的数字的末尾数字 000 ∼ 999 000\sim 999 000999构成循环节,从而对最后三位暴力算即可.
如果数字不满3位,我就干脆直接特判,节省脑子…

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
bool cmp(char x,char y){
    return x>y;
}
int cnt[11],cmc[11];
string s,nu[10][105],ss,sj;
int main(){
    ios::sync_with_stdio(0);
    int T;
    ss="0";
    for(int i=0;i<10;i++){
        ss[0]=i+'0';nu[i][0]="";
        for(int j=1;j<=100;j++)nu[i][j]=nu[i][j-1]+ss;
    }
    cin>>T;
    while(T--){
        cin>>s;
        int slen=s.length();
        if(slen<3){
            if(slen==1){
                if((s[0]-'0')%8==0){
                    cout<<s<<endl;
                }else cout<<"-1"<<endl;
            }else{
                int g=(s[1]-'0')*10+s[0]-'0',t=(s[0]-'0')*10+s[1]-'0',res=-1;
                if(g%8==0){
                    if(res<g)res=g;
                }
                if(t%8==0){
                    if(res<t)res=t;
                }
                cout<<res<<endl;
            }
            continue;
        }
        memset(cnt,0,sizeof(cnt));
        for(int i=0;i<slen;i++){
            cnt[s[i]-'0']++;
        }
        string res;bool resed=0;
        sj="000";
        for(int i=0;i<1000;i+=8){
            memset(cmc,0,sizeof(cmc));
            ss="";
            int g=i;
            for(int j=0;j<3;j++){
                cmc[g%10]++;
                sj[2-j]=g%10+'0';
                g/=10;
            }
            bool f=1;
            for(int j=0;j<10;j++){
                if(cmc[j]>cnt[j]){f=0;break;}
            }
            if(!f)continue;
            for(int j=9;j>=0;j--){
                ss+=nu[j][cnt[j]-cmc[j]];
            }
            ss+=sj;
            //cout<<"yese"<<ss<<endl;
            if(resed){
                if(res<ss)res=ss;
            }else res=ss,resed=1;
        }
        if(resed)cout<<res<<endl;else cout<<"-1"<<endl;
    }
    //system("pause");    
}

D - tokitsukaze and Inverse Number

循环移位区间 [ L , R ] k [L,R]k [L,R]k次,一共执行 Q Q Q次,每次询问得到的序列的逆序数的奇偶性.
考虑 [ L , R ] [L,R] [L,R]移动一次,那么假设 [ L , R ] [L,R] [L,R]之间有 x x x个数比第一个数大,有 a − 1 − x a-1-x a1x个数比第一个数小,那么显然答案是 o l d r e s + a − 1 − x − x ≡ o l d r e s + a − 1 ( m o d 2 ) oldres+a-1-x-x\equiv oldres+a-1 \pmod 2 oldres+a1xxoldres+a1(mod2).所以无论区间内的数字是什么,其结果只与操作数的区间长度有关.

#include <cstdio>
#include <iostream>
using namespace std;
int bit[100005];
int a[100005],n;
#define lowbit(_x) ((_x)&-(_x))
void add(int x){
    while(x<=n){
        bit[x]++;
        x+=lowbit(x);
    }
}
int sum(int x){
    int res=0;
    while(x>0){
        res+=bit[x];
        x-=lowbit(x);
    }
    return res;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    int res;
    for(int i=n;i>=1;i--){
        res+=sum(a[i]);
        add(a[i]);
        res&=1;
    }
    //printf("before %d\n",res);
    int q,l,r,k;
    scanf("%d",&q);
    while(q--){
        scanf("%d%d%d",&l,&r,&k);
        printf("%d\n",res^=(k&1)&((r-l)&1));
    }
    //system("pause");
}

E - tokitsukaze and Similar String

求串 s [ l 1 . . . r 1 ] s[l_1...r_1] s[l1...r1] s [ l 2 . . . r 2 ] s[l_2...r_2] s[l2...r2]之间的相似度.相似度如题定义.
暴力算 s s s整体移位 0 ∼ 25 0\sim 25 025次的所有hash值,暴力判断即可…

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
char s[100005];
unsigned long long HA[26][100005],HB[100005];
unsigned long long gethash(unsigned long long *Hash,int x, int len)
{
    return Hash[x + len - 1] - Hash[x - 1] * HB[len];
}
int main(){
    int n,q,slen;
    scanf("%d%s%d",&n,s+1,&q);
    int x,y,l;
    slen=strlen(s+1);
    HB[0]=1;
    for(int i=1;i<=slen;i++){
        for(int j=0;j<26;j++)HA[j][i]=HA[j][i-1]*233+(s[i]-'a'+j)%26+'a';
        HB[i]=HB[i-1]*233;
    }
    while(q--){
        scanf("%d%d%d",&x,&y,&l);
        unsigned long long hx,hy=gethash(HA[0],y,l);
        int res=-1;
        for(int j=0;j<26;j++){
            hx=gethash(HA[j],x,l);
            if(hx==hy){
                res=j;
                break;
            }
        }
        printf("%d\n",min(res,26-res));
    }
    //system("pause");
}

F - tokitsukaze and Unlimited Array

求多项式函数构造的数列 a [ i ] = f ( i ) a[i]=f(i) a[i]=f(i) N N N阶差分的级数和.
首先由 N N N阶差分的性质所有次数小于 n n n f f f项都会被差分为0.
从而在答案的贡献上 f ( x ) ≡ g ( x ) = a n x n f(x)\equiv g(x)=a_nx^n f(x)g(x)=anxn.
由差分的性质,答案等于:
r e s = a n n ! res=a_n n! res=ann!
所以答案即是求 a n n ! a_n n! ann!,由于 n n n很大,分段打表即可…

#include <iostream>
#include <cstdio>
using namespace std;
const long long mod=1e9+7;
const long long p=1000000007;
const long long N=10000000;
const long long num[]={1,682498929,491101308,76479948,723816384,
    67347853,27368307,625544428,199888908,888050723,
    927880474,281863274,661224977,623534362,970055531,
    261384175,195888993,66404266,547665832,109838563,
    933245637,724691727,368925948,268838846,136026497,
    112390913,135498044,217544623,419363534,500780548,
    668123525,128487469,30977140,522049725,309058615,
    386027524,189239124,148528617,940567523,917084264,
    429277690,996164327,358655417,568392357,780072518,
    462639908,275105629,909210595,99199382,703397904,
    733333339,97830135,608823837,256141983,141827977,
    696628828,637939935,811575797,848924691,131772368,
    724464507,272814771,326159309,456152084,903466878,
    92255682,769795511,373745190,606241871,825871994,
    957939114,435887178,852304035,663307737,375297772,
    217598709,624148346,671734977,624500515,748510389,
    203191898,423951674,629786193,672850561,814362881,
    823845496,116667533,256473217,627655552,245795606,
    586445753,172114298,193781724,778983779,83868974,
    315103615,965785236,492741665,377329025,847549272,698611116
};
long long getnum(long long n){
    if(!n)return 1;
    long long tmp=num[n/N];
    for(int i=n/N*N+1;i<=n;i++)tmp=(long long)tmp*i%p;
    return tmp;
}
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    long long x,y;
    for(int i=1;i<=m;i++){
        scanf("%lld%lld",&x,&y);
        if(y==n)break;
    }
    printf("%lld\n",x*getnum(n)%mod);
    //system("pause");
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值