• 2019icpc徐州网络赛


    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
    ",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!
    ");
                }else{
                    printf("oh, child!
    ");
                }
            }else if(tl<sl){
                int p=kmp(s,sl,t,tl);
                if(p!=-1){
                    printf("my teacher!
    ");
                }else{
                    printf("senior!
    ");
                }
            }else if(tl==sl){
                if(strcmp(t,s)==0){
                    printf("jntm!
    ");
                }else{
                    printf("friend!
    ");
                }
            }
        }
        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
    ",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?'
    ':' ');
        }
        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
    ",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;
    }
    
  • 相关阅读:
    window安装swagger editor
    DiffMerge安装配置使用
    线程池相关知识点
    JAVA程序员面试笔试宝典4
    JAVA程序员面试笔试宝典3
    JAVA程序员面试笔试宝典2
    JAVA程序员面试笔试宝典1
    Linux开启ssh服务
    面试题
    java基础学习之垃圾回收机制
  • 原文地址:https://www.cnblogs.com/zxcoder/p/11482308.html
Copyright © 2020-2023  润新知