A Who is better?

题意

excrt+斐波那契博弈

分析

Java的BigInteger对象默认为null,不能直接比较。

代码

import java.math.BigInteger;
import java.util.Scanner;

public class Main {
    static int n;
    static BigInteger[] a=new BigInteger[25];
    static BigInteger[] b=new BigInteger[25];
    static BigInteger INF=BigInteger.valueOf((long)1e15);
    static BigInteger[] fib=new BigInteger[110];
    static int cnt=0;
    static void init(){
        fib[1]=BigInteger.ONE;
        fib[2]=BigInteger.ONE;
        cnt=2;
        for(int i=3;i<110;i++){
            fib[i]=fib[i-1].add(fib[i-2]);
            if(fib[i].compareTo(INF)>0){
                break;
            }
            cnt++;
        }
    }
    static boolean check(BigInteger t){
        for(int i=1;i<=cnt;i++){
            if(fib[i]==null){
                return false;
            }
            if(fib[i].compareTo(t)==0){
                return true;
            }
        }
        return false;
    }
    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);
        init();
        n=cin.nextInt();
        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("Tankernb!");
        }else{
            if(check(ans)){
                System.out.println("Lbnb!");
            }else{
                System.out.println("Zgxnb!");
            }
        }
    }
}

B so easy

题意

两种操作,删除一个数,询问一个数(不一定还在)的后继。

分析

并查集,初始化每个数查询的答案就是本身,删除之后答案就是\(find(x+1)\),要离散化。

代码

#include <bits/stdc++.h>
using namespace std;
const int N=2e6+50;
struct Orz{
    vector<int> a;
    void init(){
        a.clear();
    }
    int siz(){
        return a.size();
    }
    void add(int x){
        a.push_back(x);
    }
    void work(){
        sort(a.begin(),a.end());
        a.erase(unique(a.begin(),a.end()),a.end());
    }
    int idx(int x){
        return lower_bound(a.begin(),a.end(),x)-a.begin()+1;
    }
    int val(int i){
        return a[i-1];
    }
}orz;
int n,q,o[N],a[N],p[N];
int find(int x){
    return x==p[x]?p[x]:p[x]=find(p[x]);
}
int main(){
    scanf("%d%d",&n,&q);
    orz.init();
    for(int i=1;i<=q;i++){
        scanf("%d%d",&o[i],&a[i]);
        orz.add(a[i]);
        orz.add(a[i]+1);
    }
    orz.work();
    int m=orz.siz();
    for(int i=1;i<=m;i++){
        p[i]=i;
    }
    for(int i=1;i<=q;i++){
        int k=orz.idx(a[i]);
        if(o[i]==1){
            if(find(k)==k){
                p[k]=find(k+1);
            }
        }else{
            int v=orz.val(find(k));
            printf("%d\n",v);
        }
    }
    return 0;
}

C Buy Watermelon

代码

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n;
    scanf("%d",&n);
    if(n%2==0 && n!=2)
    puts("YES");
    else puts("NO");
} 

D Carneginon

题意

给一个串T和多个串S,根据长度大小和是否为子串判断输出。

分析

题目说明的复杂度刚好就是暴力KMP。

代码

#include <bits/stdc++.h>
using namespace std;
const int N=1e6+50;
int n;
char s[N],t[N];
int nex[N];
void getNext(char s[],int n){
    int i=0,j=-1;
    nex[0]=-1;
    while(i<n){
        if(j==-1 || s[i]==s[j]){
            nex[++i]=++j;
        }else{
            j=nex[j];
        }
    }
}
int kmp(char s[],int n,char p[],int m){
    int i=0,j=0;
    getNext(p,m);
    while(i<n && j<m){
        if(j==-1 || s[i]==p[j]){
            i++;
            j++;
        }else{
            j=nex[j];
        }
        if(j==m){
            return i-j+1;
        }
    }
    return -1;
}
int main(){
    scanf("%s",t);
    int tl=strlen(t);
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%s",s);
        int sl=strlen(s);
        if(tl>sl){
            int p=kmp(t,tl,s,sl);
            if(p!=-1){
                printf("my child!\n");
            }else{
                printf("oh, child!\n");
            }
        }else if(tl<sl){
            int p=kmp(s,sl,t,tl);
            if(p!=-1){
                printf("my teacher!\n");
            }else{
                printf("senior!\n");
            }
        }else if(tl==sl){
            if(strcmp(t,s)==0){
                printf("jntm!\n");
            }else{
                printf("friend!\n");
            }
        }
    }
    return 0;
}

E XKC's basketball team

题意

对于每个\(a[i]\),查询右边比\(a[i]+m\)大的最远距离。

分析

不用离散化,不用主席树,不用权值线段树。。。

只需要建正常的线段树维护最大值即可,查询时尽量先走右子树。

代码

#include <bits/stdc++.h>
using namespace std;
#define ls i<<1
#define rs i<<1|1
#define mid (l+r)/2
const int N=5e5+50;
int n,m,a[N],ans[N];
int mx[N*4];
void pushup(int i){
    mx[i]=max(mx[ls],mx[rs]);
}
void build(int i,int l,int r){
    mx[i]=0;
    if(l==r){
        return;
    }
    build(ls,l,mid);
    build(rs,mid+1,r);
}
void insert(int i,int l,int r,int p){
    if(l==r && l==p){
        mx[i]=a[p];
        return;
    }
    if(p<=mid){
        insert(ls,l,mid,p);
    }else{
        insert(rs,mid+1,r,p);
    }
    pushup(i);
}
int query(int i,int l,int r,int k){
    if(l==r){
        if(mx[i]>=k){
            return l;
        }else{
            return -1;
        }
    }
    if(mx[rs]>=k){
        return query(rs,mid+1,r,k);
    }else{
        if(mx[ls]>=k){
            return query(ls,l,mid,k);
        }else{
            return -1;
        }
    }
}
void debug(int i,int l,int r){
    printf("%d %d %d\n",l,r,mx[i]);
    if(l==r){
        return;
    }
    debug(ls,l,mid);
    debug(rs,mid+1,r);
}
int main(){
//    freopen("in.txt","r",stdin);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    build(1,1,n);
    for(int i=n;i>=1;i--){
        int t=query(1,1,n,a[i]+m);
        if(t==-1){
            ans[i]=t;
        }else{
            ans[i]=t-i-1;
        }
        insert(1,1,n,i);
//
    }
    for(int i=1;i<=n;i++){
        printf("%d%c",ans[i],i==n?'\n':' ');
    }
    return 0;
}

G Colorful String

题意

定义子串的价值为不同字符个数,求出所有回文子串的价值之和。

分析

回文树模板,插入的时候由另一个回文子串转移而来,判断新加入的字符是否再上一个回文子串中出现,若否,则价值+1。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e5+50;
struct PT{
    int next[N][26];
    int vis[N][26];
    int val[N];
    int fail[N];
    int cnt[N];
    int num[N];
    int len[N];
    int S[N];
    int last;
    int id[N];
    int n;
    int p;
    int newnode(int l){
        for(int i=0;i<26;i++){
            next[p][i]=0;
        }
        cnt[p]=0;
        num[p]=0;
        len[p]=l;
        return p++;
    }
    void init(){
        p=0;
        newnode(0);
        newnode(-1);
        last=0;
        n=0;
        S[n]=-1;
        fail[0]=1;
    }
    int getFail(int x){
        while(S[n-len[x]-1]!=S[n]){
            x=fail[x];
        }
        return x;
    }
    void add(int c){
        c-='a';
        S[++n]=c;
        int cur=getFail(last);
        if(!next[cur][c]){
            int now=newnode(len[cur]+2);
            for(int i=0;i<26;i++){
                vis[now][i]=vis[cur][i];
            }
            val[now]=val[cur];
            vis[now][c]=1;
            if(!vis[cur][c]){
                val[now]++;
            }
            fail[now]=next[getFail(fail[cur])][c];
            num[now]=num[fail[now]]+1;
            next[cur][c]=now;
        }
        last=next[cur][c];
        cnt[last]++;
        id[last]=n;
    }
    void count(){
        for(int i=p-1;i>=0;i--){
            cnt[fail[i]]+=cnt[i];
        }
    }
    ll solve(){
        ll ans=0;
        for(int i=2;i<p;i++){
            ans+=1ll*val[i]*cnt[i];
        }
        return ans;
    }
}ac;
char s[N];
int main(){
//    freopen("in.txt","r",stdin);
    scanf("%s",&s);
    int len=strlen(s);
    ac.init();
    for(int i=0;i<len;i++){
        ac.add(s[i]);
    }
    ac.count();
    ll ans=ac.solve();
    printf("%lld\n",ans);
}

J Random Access Iterator

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=1e6+50;
const int mod=1e9+7;
ll dp[MAXN];
vector<int>v[MAXN];
int d[MAXN];
int ans=0;
ll q_pow(ll a,ll k)
{
    ll ans=1;
    while(k)
    {
        if(k&1)
        {
            ans*=a;
            ans%=mod;
        }
        a*=a;
        a%=mod;
        k>>=1;
    }
    return ans;
}
void dfs(int now,int pre,int x)
{
    ans=max(ans,x);
    d[now]=x;
    int l=v[now].size();
    for(int i=0;i<l;i++)
    {
        int to=v[now][i];
        if(to==pre)continue;
        dfs(to,now,x+1);
    }
}
void solve(int now,int pre)
{
    int l=v[now].size();
    if(l==1 && now!=1)
    {
        dp[now]=(d[now]==ans);
        return ;
    }
    ll ans=0;
    for(int i=0;i<l;i++)
    {
        int to=v[now][i];
        if(to==pre)continue;
        solve(to,now);
        ans+=dp[to];
        ans%=mod;
    }
    if(now!=1)l--;
    ans=ans*q_pow(l,mod-2)%mod;
    ans=(1-ans+mod)%mod;
    ans=q_pow(ans,l);
    ans=(1-ans+mod)%mod;
    dp[now]=ans;
}
int main()
{
    ios::sync_with_stdio(false);
    int n;
    cin>>n;
    for(int i=1;i<n;i++)
    {
        int x,y;
        cin>>x>>y;
        v[x].push_back(y);
        v[y].push_back(x);
    }
    dfs(1,0,1);
    solve(1,0);
    cout<<dp[1]<<endl;
//  cout<<(1-bas%mod+mod)%mod;
}

K Center

题意

给多个点,询问最少增加多少个点,使得这些点有一个中心点。

分析

枚举任意两个点,求他们的中心点,用map存每个中心点对应的点数,最后选择那个最多的。

代码

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1005;
map<pair<int,int> ,int>mp; 
pair<int,int>a[MAXN];
int ans=0;
int main()
{
    ios::sync_with_stdio(false);
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i].first>>a[i].second; 
        a[i].first*=2;
        a[i].second*=2;
        mp[a[i]]++;
        ans=max(ans,mp[a[i]]);
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=i+1;j<=n;j++)
        {
            int X=a[i].first+a[j].first,Y=a[i].second+a[j].second;
            X/=2,Y/=2;
            pair<int,int>p=make_pair(X,Y);
            mp[p]+=2;
            ans=max(ans,mp[p]);
        }
    }
    cout<<n-ans<<endl;
}

M Longest subsequence

题意

给定两个串S和T,求S的一个最长子序列满足字典序严格大于T。

代码

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e6+50;
const int inf=-1e6;
int ans=-1;
char s[MAXN],t[MAXN];
int cnt[MAXN][30];
int n,m;
int solve(int i,int j)
{
    if(j>m && i<=n) return n-i+1;
    if(i>n)return inf;
    int x=t[j]-'a'; 
    int p1=cnt[i][x];
//  cout<<i<<' '<<j<<' '<<p1<<endl;
    if(p1==0)   return inf;
    if(s[p1]>t[j])return n-p1+1;
    else if(s[p1]==t[j])
    {
        int y=x+1;
        int p2=cnt[i][y];
//      cout<<i<<' '<<j<<' '<<p1<<' '<<p2<<"????"<<endl;
        if(p2==0) return solve(p1+1,j+1)+1;
        else return max(n-p2+1,solve(p1+1,j+1)+1); 
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin>>n>>m;
    cin>>s+1>>t+1;
    for(int i=n;i>=1;i--)
    {
        int x=s[i]-'a';
        for(int j=x;j>=0;j--)
        {
            cnt[i][j]=i;
        }
        for(int j=x+1;j<26;j++)
        {
            cnt[i][j]=cnt[i+1][j];
        }
    }
    int ans=solve(1,1);
    if(ans<=0)
    cout<<-1<<endl;
    else cout<<ans<<endl;
}