B Coffee Chicken

题意

定义一个字符串的斐波那契数列,求从第k位开始的后面十个字符。

分析

  • 把第n项求出来是不可能的。
  • 斐波那契数列的增长是很快的,而且由于题目保证\(k<=min(|S(n)|,10^{12})\),且只输出十个字符,因此其实只有前几十项是有用的。
  • 把前面几十项的长度和字符串预处理出来,然后分治输出即可。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int T,n;
ll k,l[65];
string s[25];
void solve(int n,ll k,ll num){
    if(n<=20){
        for(int i=k-1,j=0;i<l[n] && j<num;i++,j++){
            printf("%c",s[n][i]);
        }
        return;
    }
    if(k+num<=l[n-2]){
        solve(n-2,k,num);
    }else if(k>l[n-2]){
        solve(n-1,k-l[n-2],num);
    }else{
        solve(n-2,k,l[n-2]-k+1);
        solve(n-1,1,num-(l[n-2]-k+1));
    }
}
int main(){
//    freopen("in.txt","r",stdin);
    l[1]=6;
    l[2]=7;
    s[1]="COFFEE";
    s[2]="CHICKEN";
    for(int i=3;i<=60;i++){
        l[i]=l[i-2]+l[i-1];
    }
    for(int i=3;i<=20;i++){
        s[i]=s[i-2]+s[i-1];
    }
    scanf("%d",&T);
    while(T--){
        scanf("%d%lld",&n,&k);
        n=min(n,60);
        solve(n,k,10);
        printf("\n");
    }
    return 0;
}

D Han Xin and His Troops

题意

拓展中国剩余定理。

分析

不会数学,负责帮队友写了个Java大数版本。

代码

import java.io.*;
import java.math.BigInteger;
import java.util.Scanner;
 
public class Main {
 
    static BigInteger[] b=new BigInteger[150];
    static BigInteger[] a=new BigInteger[150];
    static int n;
    static BigInteger m;
    public static BigInteger exgcd(BigInteger a,BigInteger b,BigInteger[] x,BigInteger[] y){
        if(a.compareTo(BigInteger.ZERO)==0 && b.compareTo(BigInteger.ZERO)==0){
            return new BigInteger("-1");
        }
        if(b.compareTo(BigInteger.ZERO)==0){
            x[0]= BigInteger.ONE;
            y[0]=BigInteger.ZERO;
            return a;
        }
        BigInteger d=exgcd(b,a.mod(b),y,x);
        y[0]=y[0].subtract(a.divide(b).multiply(x[0]));
        return d;
    }
    static BigInteger excrt(){
        BigInteger[] x=new BigInteger[2];
        BigInteger[] y=new BigInteger[2];
        BigInteger M=b[1];
        BigInteger ans=a[1];
        for(int i=2;i<=n;i++){
            BigInteger ai=M,bi=b[i],ci=(a[i].subtract(ans.mod(bi)).add(bi)).mod(bi);
            BigInteger gcd=exgcd(ai,bi,x,y);
            BigInteger bg=bi.divide(gcd);
            if(ci.mod(gcd).compareTo(BigInteger.ZERO)!=0){
                return new BigInteger("-1");
            }
            x[0]=x[0].multiply(ci.divide(gcd)).mod(bg);
            ans=ans.add(x[0].multiply(M));
            M=M.multiply(bg);
            ans=(ans.mod(M).add(M)).mod(M);
        }
        return (ans.mod(M).add(M)).mod(M);
    }
    public static void main(String[] args) {
        Scanner cin=new Scanner(System.in);
        n=cin.nextInt();
        m=cin.nextBigInteger();
        for(int i=1;i<=n;i++){
            b[i]=cin.nextBigInteger();
            a[i]=cin.nextBigInteger();
        }
        BigInteger ans=excrt();
        if(ans.compareTo(BigInteger.valueOf(-1))==0){
            System.out.println("he was definitely lying");
        }else if(ans.compareTo(m)>0){
            System.out.println("he was probably lying");
        }else{
            System.out.println(ans);
        }
    }
}

F Popping Balloons

题意

在一个二维平面有一些气球,横着打三枪竖着打三枪,要使打到的气球数最多。

分析

  • 首先肯定是行列肯定是枚举一个,维护另一个,这里我们考虑枚举列,然后维护行打三枪的最大值。
  • 考虑到列的影响,行的最值需要用线段树来维护,我们定义行\(i\)的值\(v[i]\)表示打了\(i,i+r,i+2*r\)三枪的最大值,那么枚举打了第\(j,j+r,j+2*r\)列时,这些列上对应的行的气球就被列的打掉,所以对行的贡献就没了
  • 因此对于枚举的列的每个行\(k\),将\(k,k-r,k-2*r\)\(v[k]\)贡献减去即可。

代码

#include <bits/stdc++.h>
using namespace std;
#define ls i<<1
#define rs i<<1|1
#define mid (l+r)/2
const int N=1e5+50;
const int MAX=1e5+1;
int n,R,x,y;
vector<int> g[N];
int h[N],s[N];
int mx[N*4];
void pushup(int i){
    mx[i]=max(mx[ls],mx[rs]);
}
void build(int i,int l,int r){
    if(l==r){
        mx[i]=s[l];
        if(l+R<=MAX){
            mx[i]+=s[l+R];
        }
        if(l+2*R<=MAX){
            mx[i]+=s[l+2*R];
        }
        return;
    }
    build(ls,l,mid);
    build(rs,mid+1,r);
    pushup(i);
}
void update(int i,int l,int r,int p,int v){
    if(l==r && l==p){
        mx[i]+=v;
        return;
    }
    if(p<=mid){
        update(ls,l,mid,p,v);
    }else{
        update(rs,mid+1,r,p,v);
    }
    pushup(i);
}
int main(){
//    freopen("in.txt","r",stdin);
    scanf("%d%d",&n,&R);
    for(int i=0;i<n;i++){
        scanf("%d%d",&x,&y);
        x++;
        y++;
        h[x]++;
        s[y]++;
        g[x].push_back(y);
    }
    int ans=0;
    build(1,1,MAX);
    for(int i=1;i<=MAX;i++){
        int tmp=h[i];
        int siz=g[i].size();
        for(int j=0;j<siz;j++){
            int v=g[i][j];
            update(1,1,MAX,v,-1);
            if(v-R>=1){
                update(1,1,MAX,v-R,-1);
            }
            if(v-2*R>=1){
                update(1,1,MAX,v-2*R,-1);
            }
        }
        if(i+R<=MAX){
            tmp+=h[i+R];
            siz=g[i+R].size();
            for(int j=0;j<siz;j++){
                int v=g[i+R][j];
                update(1,1,MAX,v,-1);
                if(v-R>=1){
                    update(1,1,MAX,v-R,-1);
                }
                if(v-2*R>=1){
                    update(1,1,MAX,v-2*R,-1);
                }
            }
        }
        if(i+2*R<=MAX){
            tmp+=h[i+2*R];
            siz=g[i+2*R].size();
            for(int j=0;j<siz;j++){
                int v=g[i+2*R][j];
                update(1,1,MAX,v,-1);
                if(v-R>=1){
                    update(1,1,MAX,v-R,-1);
                }
                if(v-2*R>=1){
                    update(1,1,MAX,v-2*R,-1);
                }
            }
        }
        ans=max(ans,tmp+mx[1]);
        siz=g[i].size();
        for(int j=0;j<siz;j++){
            int v=g[i][j];
            update(1,1,MAX,v,1);
            if(v-R>=1){
                update(1,1,MAX,v-R,1);
            }
            if(v-2*R>=1){
                update(1,1,MAX,v-2*R,1);
            }
        }
        if(i+R<=MAX){
            siz=g[i+R].size();
            for(int j=0;j<siz;j++){
                int v=g[i+R][j];
                update(1,1,MAX,v,1);
                if(v-R>=1){
                    update(1,1,MAX,v-R,1);
                }
                if(v-2*R>=1){
                    update(1,1,MAX,v-2*R,1);
                }
            }
        }
        if(i+2*R<=MAX){
            siz=g[i+2*R].size();
            for(int j=0;j<siz;j++){
                int v=g[i+2*R][j];
                update(1,1,MAX,v,1);
                if(v-R>=1){
                    update(1,1,MAX,v-R,1);
                }
                if(v-2*R>=1){
                    update(1,1,MAX,v-2*R,1);
                }
            }
        }
    }
    printf("%d\n",ans);
    return 0;
}

H Stammering Chemists

题意

给一个6个点的树,判断属于题目中的哪一种。

分析

根据度数判断即可。

代码

#include <bits/stdc++.h>
using namespace std;
int T,u,v,ind[10],cnt[10];
vector<int> g[10];
int main(){
//    freopen("in.txt","r",stdin);
    scanf("%d",&T);
    while(T--){
        memset(ind,0,sizeof(ind));
        memset(cnt,0,sizeof(cnt));
        for(int i=1;i<=6;i++){
            g[i].clear();
        }
        for(int i=0;i<5;i++){
            scanf("%d%d",&u,&v);
            ind[u]++;
            ind[v]++;
            g[u].push_back(v);
            g[v].push_back(u);
        }
        for(int i=1;i<=6;i++){
            cnt[ind[i]]++;
        }
        if(cnt[2]==4 && cnt[1]==2){
            printf("n-hexane\n");
        }else if(cnt[4]>0){
            printf("2,2-dimethylbutane\n");
        }else if(cnt[3]==2 && cnt[1]==4){
            printf("2,3-dimethylbutane\n");
        }else{
            int rt=0;
            for(int i=1;i<=6;i++){
                if(ind[i]==3){
                    rt=i;
                    break;
                }
            }
            int a[3]={0};
            for(auto v:g[rt]){
                a[ind[v]]++;
            }
            if(a[1]==1 && a[2]==2){
                printf("3-methylpentane\n");
            }else{
                printf("2-methylpentane\n");
            }
        }
    }
    return 0;
}