2019牛客暑期多校训练营(第十场)

B Coffee Chicken

题目链接
题意:字符串s[1]为"COFFEE",s[2]为"CHICKEN"。其中字符串s[n]为s[n-2]+s[n-1]。给定n和k,求第n个字符串的第k个字符开始连续的10个字符,当字符小于10个则输至字符串末尾。
思路:递归,根据字符串递归转移长度和下标。

#include <bits/stdc++.h>

#define maxn 505
typedef long long ll;
using namespace std;

int n;
ll k;
string s[3];
ll len[maxn];

void init(){
    len[1]=s[1].size();
    len[2]=s[2].size();
    for(int i=3;i<55;i++){
        len[i]=len[i-2]+len[i-1];
    }

}

void input(){
    scanf("%d%lld",&n,&k);
}

void solve(int n,ll k,int L){
//    cout<<n<<' '<<k<<' '<<L<<endl;
    if(n<3){
//        cout<<k-1+L<<' '<<len[n]<<endl;
        for(int i=k-1;i<min(k-1+L,len[n]);i++)
            printf("%c",s[n][i]);
        return;
    }
    if(k+9<=len[n-2])
        solve(n-2,k,L);
    else if(k>len[n-2])
        solve(n-1,k-len[n-2],L);
    else{
        solve(n-2,k,L);
        solve(n-1,1,L-len[n-2]+k-1);
    }
}

int main(){
    s[1]="COFFEE";
    s[2]="CHICKEN";
    init();
    int t;
    scanf("%d",&t);
    while(t--){
        input();
        solve(n,k,10);
        printf("\n");
    }
}

D Han Xin and His Troops

题目链接
题意:给定多组a和b,求满足的x,使得x%b==a,当x大于m和不存在时,输出特定语句,否则输出x
思路:套用扩展中国剩余定理,但存在爆ll情况,使用python、java、或__int128。

#include <bits/stdc++.h>

#define maxn 100005
typedef __int128 ll;
using namespace std;

ll n;ll m;
ll a[maxn],b[maxn];
ll ai[maxn],bi[maxn];

void scan(__int128 &x)//输入
{
    x = 0;
    int f = 1;
    char ch;
    if((ch = getchar()) == '-') f = -f;
    else x = x*10 + ch-'0';
    while((ch = getchar()) >= '0' && ch <= '9')
        x = x*10 + ch-'0';
    x *= f;
}

void input(){
    scan(n);scan(m);
    ll i;
    for(i=1;i<=n;i++){
        scan(a[i]);scan(b[i]);
//        scanf("%lld%lld",&a[i],&b[i]);
        bi[i]=a[i];
        ai[i]=b[i];
    } 
}

ll exgcd(ll a,ll b,ll &x,ll &y)
{
    if(b==0){x=1;y=0;return a;}
    ll gcd=exgcd(b,a%b,x,y);
    ll tp=x;
    x=y; y=tp-a/b*y;
    return gcd;
}

ll excrt()
{
    ll x,y,k;
    ll M=bi[1],ans=ai[1];
    //bi被余数,ai余数
    for(ll i=2;i<=n;i++)
    {
        ll a=M,b=bi[i],c=(ai[i]-ans);
        ll gcd=exgcd(a,b,x,y),bg=b/gcd;
        if(c%gcd!=0) return -1;

        x=(x*(c/gcd)%bg+bg)%bg;//快乘
        ans+=x*M;
        M=M/gcd*b;
    }
    return ans;
}

void print(__int128 x)
{
    if(x < 0)
    {
        x = -x;
        putchar('-');
    }
     if(x > 9) print(x/10);
    putchar(x%10 + '0');
}

void solve(){
    __int128 res=excrt();
    if(res==-1)
        printf("he was definitely lying\n");
    else if(res>m)
        printf("he was probably lying\n");
    else
        print(res);
}

int main(){
    input();
    solve();
}

E Hilbert Sort

题目链接
题意:定义希尔伯特曲线在2^k边长图的样子,给出n个点的坐标,求其根据曲线的顺序关系。
思路:对于每一个点递归划分,进行编码,最后根据编码排序。

#include <bits/stdc++.h>

#define maxn 1000005
typedef long long ll;
using namespace std;

int n,k;
struct node{
    int x,y;
    ll s=0;
}nod[maxn];

bool cmp(node a,node b){
    return a.s<b.s;
}

void input(){
    scanf("%d%d",&n,&k);
    int i;
    for(i=1;i<=n;i++)
        scanf("%d%d",&nod[i].x,&nod[i].y);
}

ll dg(int x,int y,int k){
//    cout<<x<<' '<<y<<' '<<k<<endl;
    int d=pow(2,k-1);
    if(k==1){
        if (x == 1 && y == 1)return 1;
        else if (x == 2 && y == 1)return 2;
        else if (x == 2 && y == 2)return 3;
        else if (x == 1 && y == 2)return 4;
    }

    if(x<=d&&y<=d){
        swap(x,y);
        return d*d*1+dg(x,y,k-1);
    }    

    if(x>d&&y<=d)
        return d*d*2+dg(x-d,y,k-1);

    if(x>d&&y>d)
        return d*d*3+dg(x-d,y-d,k-1);

    if(x<=d&&y>d){
        y=y-d;
        y=d-y+1;
        x=d-x+1;
        swap(x,y);
        return d*d*4+dg(x,y,k-1);
    }
}

void solve(){
    int i;
    for(i=1;i<=n;i++){
        nod[i].s=dg(nod[i].x,nod[i].y,k);
//        cout<<nod[i].s<<endl;
    }


    sort(nod+1,nod+1+n,cmp);
    for(i=1;i<=n;i++)
        printf("%d %d\n",nod[i].x,nod[i].y);
}

int main(){
    input();
    solve();             
}

F Popping Balloons

题目链接
题意:给你n个气球坐标x,y。你可以选择一个X坐标和Y坐标,使得X,X+R,X+2R线上的所有气球打破,使Y,Y+R,Y+2R上的气球也打破。求最多能打破多少个气球。
思路:枚举一维,例如枚举X。我们需要logn的求出最大的sum[Y]+sum[Y+R]+sum[Y+2*R],记录每个x轴上y的坐标,每次枚举时我们就可以将这些y坐标的共享-1,查询后再+1。

#include <bits/stdc++.h>

#define maxn 100005 
using namespace std;

int n,r;
int sum[maxn<<2];
int tot[maxn];
vector <int>v[maxn];

void PushUp(int rt){
    sum[rt]=max(sum[rt<<1],sum[rt<<1|1]);
}

void Build(int l,int r,int rt){
    if(l==r){
        sum[rt]=0;
        return;
    }

    int mid=(l+r)>>1;
    Build(l,mid,rt<<1);
    Build(mid+1,r,rt<<1|1);
    PushUp(rt);
}

void update(int index,int x,int l,int r,int rt){
    if(l==r)
    {
        sum[rt]+=x;
        return;
    }

    int mid=(l+r)>>1;
    if(index<=mid) update(index,x,l,mid,rt<<1);
    else update(index,x,mid+1,r,rt<<1|1);
    PushUp(rt);
}

void update(int index,int x){
    update(index,x,1,100001,1);
    if(index-r>0)
        update(index-r,x,1,100001,1);
    if(index-2*r>0)
        update(index-2*r,x,1,100001,1);
}

void input(){
    scanf("%d%d",&n,&r);
    int i,x,y;
    Build(1,100001,1);
    for(i=1;i<=n;i++){
        scanf("%d%d",&x,&y);
        x++;y++;
        tot[y]++;
        v[x].push_back(y);
    }

    for(i=1;i<=100001;i++){
        if(i+r<=100001)
            tot[i]=tot[i]+tot[i+r];
        if(i+2*r<=100001)
            tot[i]=tot[i]+tot[i+2*r];
        update(i,tot[i],1,100001,1);
    }
}

void solve(){
    int SUM,i,j; 
    int ans=0;
    for(i=1;i<=100001;i++){
        SUM=v[i].size();
        if(i+r<=100001)
            SUM+=v[i+r].size();
        if(i+2*r<=100001)    
            SUM+=v[i+2*r].size();

        int x=i;
        for(j=0;j<v[x].size();j++)
            update(v[x][j],-1);    

        if(x+r<=100001){    
            for(j=0;j<v[x+r].size();j++)
                update(v[x+r][j],-1);
        }

        if(x+2*r<=100001){
            for(j=0;j<v[x+2*r].size();j++)
                update(v[x+2*r][j],-1);
        }

//        cout<<SUM<<' '<<sum[1]<<endl;
        ans=max(ans,SUM+sum[1]);

        for(j=0;j<v[x].size();j++)
            update(v[x][j],1);

        if(x+r<=100001){    
            for(j=0;j<v[x+r].size();j++)
                update(v[x+r][j],1);
        }

        if(x+2*r<=100001){
            for(j=0;j<v[x+2*r].size();j++)
                update(v[x+2*r][j],1);
        }    
    }
    printf("%d",ans);
}

int main(){
    input();
    solve();
}

H Stammering Chemists

题目链接
题意:给你一个6个结点的树,判断为题目中的哪一种树。
思路:根据树的度、节点判断。

#include <bits/stdc++.h>

#define maxn 10
using namespace std;

int indeg[maxn];
vector <int>G[maxn];
void input() {
    int i;
    int x, y;
    for (i = 0; i<5; i++) {
        scanf("%d%d", &x, &y);
        G[x].push_back(y);
        G[y].push_back(x);
        indeg[x]++;
        indeg[y]++;
    }
}

void solve() {
    int i;
    int maxx1 = -1, maxx2 = -1;
    int maxi = -1;
    for (i = 1; i <= 6; i++)
    {
        if (indeg[i]>maxx1) {
            maxx2 = maxx1;
            maxx1 = indeg[i];
            maxi = i;
        }
        else if (indeg[i]>maxx2) {
            maxx2 = indeg[i];
        }
    }

    if (maxx1 == 4)
        printf("2,2-dimethylbutane\n");
    else if (maxx1 == 2)
        printf("n-hexane\n");
    else if (maxx1 == 3 && maxx2 == 3)
        printf("2,3-dimethylbutane\n");
    else {
        int cnt = 0;
        for (i = 0; i<G[maxi].size(); i++) {
            if (indeg[G[maxi][i]] == 1)
                cnt++;
        }

        if (cnt == 2)
            printf("2-methylpentane\n");
        else
            printf("3-methylpentane\n");
    }
}

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        memset(indeg, 0, sizeof indeg);
        for (int i = 1; i <= 6; i++)
            G[i].clear();
        input();
        solve();
    }
}