1. 程式人生 > >牛客練習賽33 - ABCD

牛客練習賽33 - ABCD

A - tokitsukaze and Counting

題目描述

給出3個整數L,R,x。tokitsukaze想知道,閉區間[L,R]中,x的倍數出現了幾次。

輸入描述:

第一行包括一個正整數T(T<=1000),表示T組資料。

接下來T行,每行包括3個正整數L,R,x。

1≤L≤R≤10^18

1≤x≤10^18

輸出描述:

輸出T行,每一行一個整數,表示答案。

 

示例1

輸入

複製

1
2 5 3

輸出

複製

1

程式碼如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<cmath>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

const int INF=0x3f3f3f3f;
const int N=105;
int a[N];
int main(){
    int t;
    ll L,R,x;
    scanf("%d",&t);
    while(t--){
        scanf("%lld%lld%lld",&L,&R,&x);
        ll ans=R/x-(L-1)/x;
        printf("%lld\n",ans);
    }
}

B - tokitsukaze and RPG - 暴力+剪枝

題目描述

tokitsukaze最近沉迷一款RPG。
這個RPG一天有k分鐘,每一天從第1分鐘開始。
有n種怪物,第i種怪物每天第一次出現的時間為Xi分鐘,第二次出現的時間為2*Xi分鐘,第三次出現的時間為3*Xi分鐘......同一時刻出現的怪物種類越多,打怪獲得的經驗也越高。
為了高效練級,tokitsukaze想知道在一天內出現怪物種類最多的時間點會出現多少種怪物,這樣的時間點有多少個。

輸入描述:

第一行包括2個正整數n,k(1≤n≤10^5,1≤k≤10^6),表示有n種怪物,一天有k分鐘。
接下來一行包括n個正整數X(1≤Xi≤10^6),含義如題面所示。

輸出描述:

輸出一行,包括兩個整數a,b。
a表示怪物種類數,b表示時間點的個數。

 

示例1

輸入

複製

3 6
2 2 3

輸出

複製

3 1

說明

在第6分鐘時,3種怪物都出現了。

示例2

輸入

複製

3 5
2 2 3

輸出

複製

2 2

說明

在第2分鐘和第4分鐘時,第一種和第二種怪物出現了。

示例3

輸入

複製

6 10
1 2 3 4 5 6

輸出

複製

4 1

說明

在第6分鐘時,出現了第一種、第二種、第三種、第六種怪物。

示例4

輸入

複製

3 5
6 6 6

輸出

複製

0 5

說明

在第1分鐘、第2分鐘、第3分鐘、第4分鐘、第5分鐘,都沒有出現怪物。

 思路:

用類似埃氏篩素數的方法去求每個數的倍數,但是這樣會超時,我們把每個數出現的次數計算出來,然後篩的時候直接加上次數就可以啦,這是一個剪枝的好方法啊,以後遇到超時的時候,就要考慮是不是我們重複計算了重複出現的數!

程式碼如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<cmath>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

const int INF=0x3f3f3f3f;
const int N=1000005;
int bei[N],a[N],ci[N];
int num[N],vis[N];
int main(){
    int n,k,tmp,mm=0;
    scanf("%d%d",&n,&k);
    for(int i=0;i<n;i++){
        scanf("%d",&tmp);
        if(vis[tmp]==0){a[mm++]=tmp;vis[tmp]=1;}
        ci[tmp]++;
    }
    for(int i=0;i<mm;i++){
        for(int j=a[i];j<=k;j+=a[i])bei[j]+=ci[a[i]];
    }
    int maxx=-1;
    for(int i=1;i<=k;i++){
        if(bei[i]>maxx){
            maxx=bei[i];
        }
        num[bei[i]]++;
    }
    printf("%d %d\n",maxx,num[maxx]);
}

C - tokitsukaze and Number Game - 模擬

題目描述

tokitsukaze又在玩3ds上的小遊戲了,現在她遇到了難關。
tokitsukaze得到了一個整數x,並被要求使用x的每一位上的數字重新排列,組成一個能被8整除的數,並且這個數儘可能大。
聰明的你們請幫幫可愛的tokitsukaze,如果無法組成被8整除的數,請輸出-1。
保證輸入不含前導0,輸出也不能含前導0。

輸入描述:

第一行包括一個正整數T(T<=1000),表示T組資料。
接下來T行,每一行包括一個整數x,(0≤x≤10^100)。

輸出描述:

請輸出用這些數字組成出能被8整除的最大的數,如果無法組成出能被8整除的數,請輸出-1。

示例1

輸入

複製

2
666
1256

輸出

複製

-1
6512

思路:

能被8整除的數字的特點是後三位能被8整除,然後對於只有1,2位的數字我們直接判斷,對於3位及以上的數字,我們從0開始一直到992,(注意0看成是000,8看成是008,這樣數字1000,1008,等就可以被判斷到啦)判斷後三位是這些數成立不成立,若是成立的話,我們再把剩餘的數字從大到小排列組成一個最大的數字,最後找出組成數字裡最大的那一個!

(其中判斷最後三位也是有技巧的,具體見程式碼註釋,剛開始寫的繞來繞去,後來改了,這樣還挺簡潔qwq)

程式碼如下:

#include<iostream>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<cmath>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

const int INF=0x3f3f3f3f;
const int N=105;
int q=0,a[N],res[1000],num[15];

void solve(int x){
    int y=(x%10)*10+x/10;
    int aa=max(x,y),bb=min(x,y);
    if(aa%8==0)printf("%d\n",aa);
    else if(bb%8==0)printf("%d\n",bb);
    else printf("-1\n");
    return ;
}

int main(){
    int t;
    char ch;
    for(int i=0;i<1000;i++){
        if(i%8==0)res[q++]=i;
    }
    scanf("%d",&t);
    getchar();
    while(t--){
        memset(a,0,sizeof(a));
        memset(num,0,sizeof(num));
        int k=0;
        while((ch=getchar())!='\n'){
            a[k++]=ch-'0';
            num[ch-'0']++;
        }
        if(k==1){//判斷只有一位的情況
            if(a[0]==8||a[0]==0)printf("%d\n",a[0]);
            else printf("-1\n");
            continue;
        }
        if(k==2){//判斷只有兩位的情況
            solve(a[0]*10+a[1]);
            continue;
        }
        string str="";
        for(int i=0;i<q;i++){//判斷三位以上的情況
            int tmp=res[i];
            int t1=tmp%10;tmp/=10;
            int t2=tmp%10;tmp/=10;
            int t3=tmp;
            num[t1]--;num[t2]--;num[t3]--;
            string s1;
            s1+=t3+'0';s1+=t2+'0';s1+=t1+'0';
            if(num[t1]>=0&&num[t2]>=0&&num[t3]>=0){//如果能滿足要求
                string s2;
                for(int i=9;i>=0;i--){//從9開始(因為9最大),加上每個數的個數
                    for(int j=0;j<num[i];j++){
                        s2+=i+'0';
                    }
                }
                s2+=s1;//最後再加上後三位
                if(s2>str)str=s2;//選擇最大的數
            }
            num[t1]++;num[t2]++;num[t3]++;
        }
        if(str=="")cout<<-1<<endl;
        else cout<<str<<endl;
    }
}

D - tokitsukaze and Inverse Number - 線代的概念or找規律

題目描述

tokitsukaze給你一個長度為n的序列,這個序列是1到n的一種排列。
然後她會進行q次操作。每次操作會給你L R k這三個數,表示區間[L,R]往右移動k次。
移動一次的定義是:一個數的位置是P(L≤P≤R-1),它往右移動後就會在P+1這個位置上;如果一個數在R這個位置,它會移動到L這個位置。
在每次操作結束後,tokitsukaze想讓你算出現在這個序列的逆序數的多少,簡單起見,你只需要告訴她現在這個序列的逆序數是奇數還是偶數就行了。
提示:序列的逆序數指的是:a[i]>a[j](i<j),滿足條件的(i,j)的個數。

輸入描述:

第一行包括一個正整數n(1≤n≤10^5)。
接下來一行,包括一個長度為n的序列,序列為1到n的一種排列。
第三行包括一個正整數q(1≤q≤10^5)。
接下來q行,每行包括三個正整數L,R,k(1≤L≤R≤n,1≤k≤10^9)。
所有變數的含義題面均有給出。

輸出描述:

在每次操作後,逆序數如果是奇數,就輸出1,如果是偶數,就輸出0。

 

示例1

輸入

複製

4
2 3 1 4
3
1 3 2
2 4 1
2 3 1

輸出

複製

0
0
1

說明

原序列為:2 3 1 4
第一次操作後,序列變為:3 1 2 4,逆序數為2,所以答案為0。
第二次操作後,序列變為:3 4 1 2,逆序數為4,所以答案為0。
第三次操作後,序列變為:3 1 4 2,逆序數為3,所以答案為1。

思路:

結論:1 到 n 的排列,任意交換兩個數,逆序數奇偶性發生

因此我們只需要知道,要經過多少次變換就可以啦

程式碼如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<cmath>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

const int INF=0x3f3f3f3f;
const int N=100005;
ll ans=0;
int a[N],b[N];
void Merge(int s[],int t[],int b,int m,int e){
    int i=b,j=m+1,k=0;
    while(i<=m&&j<=e){
        if(s[i]>s[j]){
            ans+=m-i+1;
            t[k++]=s[j++];
        }
        else t[k++]=s[i++];
    }
    while(i<=m)t[k++]=s[i++];
    while(j<=e)t[k++]=s[j++];
    for(int q=0;q<k;q++)s[q+b]=t[q];
}

void Msort(int s[],int t[],int b,int e){
    if(b<e){
        int m=(b+e)>>1;
        Msort(s,t,b,m);
        Msort(s,t,m+1,e);
        Merge(s,t,b,m,e);
    }
}

int main(){
    int n,q,l,r,k;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",&a[i]);
    }
    Msort(a,b,0,n-1);
    scanf("%d",&q);
    ans%=2;
    while(q--){
        scanf("%d%d%d",&l,&r,&k);
        k%=(r-l+1);
        ans=(ans+((r-l)%2*k)%2)%2;
        printf("%lld\n",ans%2);
    }
}