2019徐州网络赛

链接:https://www.jisuanke.com/contest/3005?view=challenges

A. Who is better?

拓展欧几里得+斐波那契博弈

#include<algorithm>
#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
ll f[80]={1,1};
ll ex_gcd(ll a,ll b,ll& x,ll& y)
{
    if(b==0)
    {
        x=1,y=0;
        return a;
    }
    ll r,tx,ty;
    r=ex_gcd(b,a%b,tx,ty);
    x=ty;
    y=tx-a/b*ty;
    return r;
}
void pre()
{
    for(int i=2;i<80;i++) f[i]=f[i-1]+f[i-2];
}
int main()
{
    pre();
    ll i,n,a1,r1,a2,r2,ans,a,b,c,d,x0,y0;
    scanf("%lld",&n);
        bool flag = 1;
        scanf("%lld%lld",&a1,&r1);
        for( i=1;i<n;i++){
            scanf("%lld%lld",&a2,&r2);
            a = a1;
            b = a2;
            c = r2-r1;
            ll d = ex_gcd(a,b,x0,y0);
            if(c%d!=0){
                flag = 0;
            }
            int t = b/d;
            //printf("%lld\n",d);
            //printf("%lld\n",x0);
            x0 = (x0*(c/d)%t+t)%t;//保证x0为正
            r1 = a1*x0 + r1;
            a1 = a1*(a2/d);


        }
        if(!flag){
            puts("Tankernb!");
            return 0;
        }
        if(r1>1e15){
            puts("Tankernb!");
            return 0;
        }
        //printf("%lld\n",r1);
        bool ff=0;
        for(int j=1;j<80;j++)
        {
            if(f[j]==r1)
            {
                ff=1;
                break;
            }
        }
        if(ff) cout<<"Lbnb!"<<endl;
        else cout<<"Zgxnb!"<<endl;
    
    return 0;
}

B. so easy

并查集离散化

用unordered_map会炸

#include<bits/stdc++.h>
#define MAXN 2000005
#define ll long long
using namespace std;
int b[MAXN];
int val[MAXN];
int f[MAXN];

int get(int x)
{
    if(f[x]!=x)
        f[x]=get(f[x]);
    return f[x];
}
void init()
{
    for(int i=0;i<MAXN;i++)
        f[i]=i;
}

int x[MAXN],y[MAXN];

int main()
{
    init();
    int n,m;
    scanf("%d%d",&n,&m);
    int num=0;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x[i],&y[i]);
        b[++num]=y[i];
        b[++num]=y[i]+1;
    }
    sort(b+1,b+num+1);
    num=unique(b+1,b+num+1)-b-1;
    for(int i=1;i<=m;i++)
    {
        int t=y[i];
        y[i]=lower_bound(b+1,b+num+1,y[i])-b;
        val[y[i]]=t;
        val[y[i]+1]=t+1;
    }
    for(int i=1;i<=m;i++)
    {
        if(x[i]==1)
        {
            int xx=get(y[i]);
            int yy=get(y[i]+1);
            f[xx]=yy;
        }
        else{
             int cnt=val[get(y[i])];
            if(cnt==n+1)
                printf("-1\n");
            else
                printf("%d\n",cnt);

        }
    }
    return 0;
}

C. Buy Watermelon

签到,>=4&&偶数

D. Carneginon

kmp搞搞,或者模拟

#include<iostream>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
int Next[100010];
string M,N;
void getNext()
{
	int len=M.length();
	Next[0]=-1;
	int i=0,j=-1;
 	while(i<len)
 	{
 		if(j==-1||M[i]==M[j])
 			Next[++i]=++j;
		else j=Next[j];
	}
}
int Kmp()
{
	int len1=M.length(),len2=N.length();
	int cnt=0,i=-1,j=-1;
	while(j<len2)
	{
		if(i==-1||M[i]==N[j])
		{
			i++,j++;
			if(i==len1)
			{
				cnt++;
			}
		}
		else i=Next[i];
	}
	return cnt;
}
int main()
{
    string T,S;
    int t;
    cin>>T>>t;
    int n=T.length();
    while(t--)
    {
        cin>>S;
        int m=S.length();
        if(m==n)
        {
            if(T==S) cout<<"jntm!"<<endl;
            else cout<<"friend!"<<endl;
        }
        else if(m>n)
        {
            M=T;N=S;
            getNext();
            if(Kmp()) cout<<"my teacher!"<<endl;
            else cout<<"senior!"<<endl;
        }
        else
        {
            M=S;N=T;
            getNext();
            if(Kmp()) cout<<"my child!"<<endl;
            else cout<<"oh, child!"<<endl;
        }
    }
    return 0;
}

 E. XKC's basketball team

预处理从后往前的最大值,然后二分

#include<bits/stdc++.h>
#define ll long long
#define MAXN 500005
using namespace std;
int maxs[MAXN],a[MAXN];

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(int i=n;i>=1;i--)
        maxs[i]=max(maxs[i+1],a[i]);

    for(int i=1;i<=n;i++)
    {
        int l=i+1,r=n;
        int ans=-1;
        while(l<=r)
        {
            int mid=(l+r)>>1;
            if(a[i]+m<=maxs[mid])
            {
                l=mid+1;
                ans=max(ans,mid);
            }
            else{
                r=mid-1;
            }
        }
        if(ans==-1)
            printf("-1");
        else
            printf("%d",ans-i-1);
        if(i!=n)
            printf(" ");
    }
    printf("\n");
    return 0;
}

G. Colorful String

回文树

  回文树:

        其实可以说是两棵树,一棵是奇树、一棵是偶树。而回文树中

                nex数组:指向的串为当前串两端加上同一个字符构成

                fail数组:fail跳转到自己这个串的最长回文后缀 

Snipaste_2019-08-04_14-11-14

实线为nex指向节点。虚线为fail指向节点

用深搜搜索这棵树,遍历每个子串的情况

#include<bits/stdc++.h>
#define ll long long
#define sigma_size 30
#define MAXN 600005
using namespace std;
char p[MAXN];

struct PAM{
    ll ans=0;
    int siz[30];
	int nex[MAXN][sigma_size];		//字符表的大小
	int fail[MAXN];
	int cnt[MAXN];	     // 节点i表示的回文串在S中出现的次数(建树时求出的不是完全的,count()加上子节点以后才是正确的)
	int num[MAXN]; 		//以节点i回文串的末尾字符结尾的但不包含本条路径上的回文串的数目。(也就是fail指针路径的深度)
	int len[MAXN];     //节点i的回文串的长度 	2~p-1()
	int S[MAXN];	  //表示第i次添加的字符	//    2~p-1
	int last,n,p;	 //p-2是不同回文串个数
					//last指向最新添加的回文结点
	int newnode(int rt){//新建节点
		memset(nex[p],0,sizeof(nex[p]));
		cnt[p]=0;
		num[p]=0;
		len[p]=rt;
		return p++;
	}
	void init(){//初始化
	    ans=0;
		p=last=n=0;
		newnode(0);
		newnode(-1);
		S[0]=-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=c-'a';
		S[++n]=c;
		int cur=getFail(last);
		if(!nex[cur][c]){
			int now=newnode(len[cur]+2);
			fail[now]=nex[getFail(fail[cur])][c];
			nex[cur][c]=now;
			num[now]=num[fail[now]]+1;
		}
		last=nex[cur][c];
		cnt[last]++;
	}
	void count1()//求每个回文子串的个数
	{
		for (int i = p-1; i >= 0; i--)
        	cnt[ fail[i] ] += cnt[i];
	}

	void dfs(int rt,int s)//根,个数
	{
	    for(int i=0;i<26;i++)//遍历扩展的每一种回文子串的情况
        {
            if(!nex[rt][i])
                continue;
            if(siz[i]){
                ll ts=s;
                ans+=(ts*cnt[nex[rt][i]]);//本质不同的回文子串数目*不同字母个数
                dfs(nex[rt][i],ts);
            }
            else{
                siz[i]++;
                ll ts=s+1;
                ans+=(ts*cnt[nex[rt][i]]);
                dfs(nex[rt][i],ts);
                siz[i]--;
            }
        }
	}
    void solve(char str[])
    {
        init();
        int Size=strlen(str);
        for(int i=0;i<Size;i++)
            add(str[i]);
        count1();//计算本质不同回文子串的个数
        dfs(0,0);//偶根
        memset(siz,0,sizeof(siz));
        dfs(1,0);//奇根
        printf("%lld\n",ans);
    }
}pam;

int main()
{
    pam.init();
    cin>>p;
    pam.solve(p);
    return 0;
}

I. query

树状数组离线询问,单调递增插每个a[i]的贡献.

我们查询分两个,一个按l排序,一个按r排序,用l排序的为了处理(1,l-1)对(l,r)产生的影响

for(i->n),边查边插入,每到一个i点,减掉左端点在这里的区间和,     去除(1,l-1)对(l,r)产生的影响,查询右端点在i处的区间和(这里已经处理了左端点).

#include<bits/stdc++.h>
#define ll long long
#define lowbit(x)  (x)&(-x)
#define MAXN 200005
using namespace std;
int a[MAXN],pos[MAXN];
int sum[MAXN];
int ans[MAXN];
int n;

struct node
{
    int l,r,id;
}aa[MAXN],bb[MAXN];

bool aac(node a,node b)
{
    return a.l<b.l;
}

bool bbc(node a,node b)
{
    return a.r<b.r;
}

void add(int x,int val)
{
    for(int i=x;i<=n;i+=lowbit(i))
        sum[i]+=val;
}

ll query(int x)
{
    ll ans=0;
    for(int i=x;i>0;i-=lowbit(i))
        ans+=sum[i];
    return ans;
}

int main()
{
    int m,l,r;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        pos[a[i]]=i;
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&l,&r);
        if(l>r)swap(l,r);
        aa[i]=bb[i]=node{l,r,i};
    }
    sort(aa+1,aa+m+1,aac);
    sort(bb+1,bb+m+1,bbc);
    for(int i=1,j=1,k=1;i<=n;i++)
    {
        while(j<=m&&aa[j].l==i)
            ans[aa[j].id]-=query(aa[j].r)-query(aa[j].l-1),j++;
        for(int p=a[i];p<=n;p+=a[i])
            add(pos[p],1);
        while(k<=m&&bb[k].r==i)
            ans[bb[k].id]+=query(bb[k].r)-query(bb[k].l-1)-(bb[k].r-bb[k].l+1),k++;
    }
    for(int i=1;i<=m;i++)
        printf("%d\n",ans[i]);
    return 0;
}

K. Center

对称点必然是一些线的中点

每个点之间相连,会得到一些中点,与其他点计算+2,与自己计算+1(自己就是中点)

遍历每一种情况,看最多省多少点

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<map>
#define ll long long
using namespace std;
struct node{
    int x,y;
}a[1010];
map<pair<int,int>,int> mp;
int n;
int main()
{
    mp.clear();
    scanf("%d",&n);
    for(int i=0;i<n;i++) scanf("%d%d",&a[i].x,&a[i].y);
    for(int i=0;i<n;i++)
    {
        mp[make_pair(a[i].x*2,a[i].y*2)]+=1;
        for(int j=1+i;j<n;j++)
        {
            int cx=a[i].x+a[j].x;
            int cy=a[i].y+a[j].y;
            mp[make_pair(cx,cy)]+=2;
        }
    }
    int ansx,ansy,ansc=0;
    for(map<pair<int,int>,int>:: iterator it=mp.begin();it!=mp.end();it++)
    {
        if(it->second>ansc)
        {
            ansc=it->second;
            ansx=it->first.first;
            ansy=it->first.second;
        }
    }
    //cout<<ansx<<' '<<ansy<<endl;
    cout<<n-mp[make_pair(ansx,ansy)]<<endl;
    return 0;
}

M. Longest subsequence

模拟,注意剪枝

#include<bits/stdc++.h>
#define MAXN 1000005
#define ll long long
using namespace std;
char pp[MAXN],ss[MAXN];
int nt[MAXN][26];

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    scanf("%s%s",pp+1,ss+1);
    for(int i=n;i>=1;i--){
        for(int j=0;j<26;j++){
            nt[i-1][j]=nt[i][j];
        }
        nt[i-1][pp[i]-'a']=i;
    }
    int ans=0,st=0;
    for(int i=1;i<=m;i++)
    {
        int c=ss[i]-'a';
        for(int j=c+1;j<26;j++)
        {
            int v=nt[st][j];
            if(v==0)
                continue;
            ans=max(ans,i-1+(n-v+1));
        }
        int g=nt[st][c];
        if(g==0){
            break;
        }
        else{
            if(i==m&&g<n){
                ans=max(ans,i+(n-g));
                break;
            }
            st=g;
        }
    }
    if(ans==0)
        printf("-1\n");
    else
        printf("%d\n",ans);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值