2019 icpc徐州区域网络赛题解09.07

A题:
链接:https://nanti.jisuanke.com/t/41383


思路:模型是经典常见的斐波拉契博弈模型,套上一个java大数的扩展中国剩余定理即可。
扩展中国剩余定理解出方程,判断一下解出的数是否是斐波拉契数即可。
代码是java的就不贴了。

B题:
链接:https://nanti.jisuanke.com/t/41384


思路:
map加路径压缩,其实就是类似于并查集找fa一样,不过是用map存储fa数组的,(因为点的个数1e9个,数组开不下),使用unordered_map并且判断没有被map映射过时用的是!mp.count(x),直接判断mp[x]的值是不是0来判断是否被map标记过时不管这一点的map值是不是0都会再把这个点加入到map一次,可能会t。
(ps:听说直接map标记然后暴力向后面找没有t,这数据简直弱的。。orzz)

AC代码:

#include<bits/stdc++.h>
using namespace std;
unordered_map<int,int> mp;
const int maxn=1e6+50;
int n,m;

int find(int x)
{
	if(!mp.count(x)) return x;
	else
	{
		return mp[x]=find(mp[x]);
	}
	return mp[x];
}
int main()
{
	scanf("%d%d",&n,&m);
	while(m--)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		if(a==1) mp[b]=find(b+1);
		else printf("%d\n",find(b));
	}
	return 0;
 } 

C题:
链接:https://nanti.jisuanke.com/t/41385


思路:本场最简单的签到题,思路是把一个西瓜切成两部分,(注意,切出来的两部分不一定要完全相等的两部分),如果存在一种切法使得切出来的两部分的质量都是偶数,就输出YES,否则就输出NO。
判断一下是不是偶数,奇数肯定不行,偶数的话2要特判不行,别的偶数都输出YES。

AC代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n;
	cin>>n;
	if(n==2)
	{
		cout<<"NO"<<endl;
		return 0;
	}
	else
	{
		if(n%2==1) cout<<"NO"<<endl;
		else cout<<"YES"<<endl;
	}
	return 0;
}

D题:
链接:https://nanti.jisuanke.com/t/41386


思路:题目意思就是一个模式串和很多个文本串,大概就是对于每一个文本串比较一下模式串和文本串的长度大小,然后对于>,<,=三种情况分别判断一下子串关系对应输出2*3种不同的字符串就行了。
一开始想的是对于比模式串长度小和等于的那些串统一用AC自动机处理,对于长度大于模式串的使用kmp来判断子串关系,这样可能不会超时,后来一看所有的字符串的总长度的和不超过1e7,给的1s好像kmp就直接能跑过去并且过的人那么多,就直接写了kmp莽过去了。

AC代码:kmp裸题了

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+500;
char s1[maxn];
char s2[maxn];
int q;


int nxt[maxn];

void get_next(char *str)
{
	int i=0;int j=-1;nxt[0]=-1;
	int len=strlen(str);
	while(i<len)
	{
		if(j==-1||str[i]==str[j]) nxt[++i]=++j;
		else j=nxt[j];
	}
}

int kmp(char *s1,char *s2)
{
	get_next(s2);
	int len=strlen(s2);
	int i,j;i=j=0;
	int len1=strlen(s1);int len2=strlen(s2);
	while(i<len1)
	{
		if(j==-1||s1[i]==s2[j]) i++,j++;
		else j=nxt[j];
		if(j>=len2)
		{
			return 1;
		}
	}
	return 0;
}


int main()
{
	scanf("%s",s1);
	scanf("%d",&q);
	while(q--)
	{
		scanf("%s",s2);
	int n1=strlen(s1);
	int n2=strlen(s2);
	if(n1==n2)
	{
		int fin=kmp(s1,s2);
		if(fin) printf("jntm!\n");
		else printf("friend!\n");
	}
	if(n1>n2)
	{
		int fin=kmp(s1,s2);
		if(fin) printf("my child!\n");
		else printf("oh, child!\n");
	}
	if(n1<n2)
	{
		int fin=kmp(s2,s1);
		if(fin) printf("my teacher!\n");
		else printf("senior!\n");
	}
	}
	return 0;
}

E题:
链接:https://nanti.jisuanke.com/t/41387


思路:学长说是权值线段树裸题,直接敲过去了,题解好像说了一个更简单好实现的方法,稍后如果补了就发上来。

G题:
链接:https://nanti.jisuanke.com/t/41389


思路:学长回文自动机写的,好像是回文自动机和dfs啥的,我是真实躺狗石锤了。

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=3e5+10;
char s[300010];
int Len;
ll ans;
struct PAM{
    ll next[maxn][26],fail[maxn],len[maxn];;
    ll txt[maxn];
    ll root0,root1,last,size;
    ll tot;
    ll mx;
    ll num[maxn];
    ll sum;
	ll cnt[maxn];
    void init(){
        last=tot=size=0; txt[size]=-1;mx=0;sum=0; 
        memset(cnt,0,sizeof(cnt));
        memset(num,0,sizeof(num));
        root0=newnode(0); root1=newnode(-1);
        fail[root0]=1; fail[root1]=0;
    }
    int newnode(int l){
        len[tot]=l;
        mx=max(mx,l*1ll); 
        memset(next[tot],0,sizeof(next[tot]));
        tot++; return tot-1;
    }
    int getfail(int x){
        while(txt[size-len[x]-1]!=txt[size]) x=fail[x];
        return x;
    }
    void extend(int c){
        txt[++size]=c; int now=getfail(last);
        if(!next[now][c]){
            int tmp=newnode(len[now]+2);
            fail[tmp]=next[getfail(fail[now])][c];
            next[now][c]=tmp;
            num[tmp]=num[fail[tmp]]+1;
        }
        last=next[now][c];
        cnt[last]++;
        sum+=num[last];
    }
    void cal(){
    	for(int i=tot;i>=2;i--){
    	  cnt[fail[i]]+=cnt[i];
		} 
	}
	void dfs(int u,int color,int res){
	   ans+=1ll*res*cnt[u];
	   for(int i=0;i<26;i++){
	   	 if(next[u][i]){
	   	    if(color&(1<<i)){//颜色出现过 
	   	       dfs(next[u][i],color,res);
			}else{
			   dfs(next[u][i],color|(1<<i),res+1);	
			}	
		 }
	   }	
	}

}pam;
int main(){
    //ios::sync_with_stdio(false); 
        scanf("%s",&s);
        ans=0;
    	pam.init();
        Len=strlen(s);
    	for(int i=0;i<Len;i++) pam.extend(s[i]-'a');
    	pam.cal();
    	pam.dfs(0,0,0);
    	pam.dfs(1,0,0);
    	printf("%lld\n",ans);
    return 0;
}

K题
链接:https://nanti.jisuanke.com/t/41393


思路:


M题:
链接:https://nanti.jisuanke.com/t/41395


思路:吃个饭回来补,好饿。

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+50;
char s1[maxn];
char s2[maxn];
vector<int> pos[30];
int n,m;
int main()
{
	scanf("%d%d",&n,&m);
	scanf("%s",s1+1);
	scanf("%s",s2+1);
	for(int i=1;i<=n;i++)
	{
		int z=s1[i]-'a';
		pos[z].push_back(i);
	 }
	vector<int>::iterator it1;
	vector<int>::iterator it2; 
	int mx=-1;
	int flag1=1;
	int now=-1;
	int cnt=0;
	for(int i=1;i<=m;i++)
	{
		if(!flag1) break;
		int z=s2[i]-'a';
		for(int j=z+1;j<='z'-'a';j++)
		{
			it1=upper_bound(pos[j].begin(),pos[j].end(),now);
			if(it1==pos[j].end()) continue;
			else//找到了大的方案 
			{
				int jj=*it1;
				mx=max(mx,n-jj+1+cnt);
			}
 		}
 		
 		it2=upper_bound(pos[z].begin(),pos[z].end(),now);
 		if(it2==pos[z].end()) flag1=0;
 		else
 		{
 			int jj=*it2;
 			now=jj;
 			cnt++;
 			if(cnt==m)
 			{
 				if(n-now==0) continue; 
 				else mx=max(mx,cnt+n-now);
			 }
		 }
	}
	printf("%d\n",mx);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值