2021ccpc华为云

question:

第五题:https://acm.hdu.edu.cn/showproblem.php?pid=7091

找所给字符串是否在原字符串中与其相同字符串有重复,是Yes否No

 thought:

对s建SAM,用set+启发式合并维护parent树上每个节点的endpos集合,由于合并时只会向set中加入节点,所以容易维护每个节点u的endpos集合中任意两个元素的最小差值,记为ans[u],只需在插入时用当前元素和其前后两个元素的差值更新当前节点的答案。对于每个询问,先倍增跳到parent树上对应的节点u上,再比较串长和ans[u]即可。

#include <bits/stdc++.h>
#define pb(x) emplace_back(x)
using namespace std;
using P=pair<int,int>;
typedef long long ll;
const int N=200005,M=26;
char S[N];
int n,m,x,y;
vector<int> e[N];
int anc[N][21],ans[N],id[N];
set<int> s[N];
struct sam{
	int fa[N],len[N],lst,gt,ch[N][M],pos[N];
	void init(){gt=lst=1;}
	void init2(){
		for(int p=1;p<=gt;p++){
			id[p]=0;ans[p]=n+1;fa[p]=0;
			e[p].clear();
			s[p]=move(set<int>{});
			for(int i=0;i<M;i++)if(ch[p][i])ch[p][i]=0;
		}
		lst=gt=1;
	}
	void ins(int c,int id){
		int f=lst,p=++gt;lst=p;
		len[p]=len[f]+1;pos[p]=id;
		while(f&&!ch[f][c])ch[f][c]=p,f=fa[f];
		if(!f){fa[p]=1;return ;}
		int x=ch[f][c],y=++gt;
		if(len[x]==len[f]+1){gt--;fa[p]=x;return ;}
		len[y]=len[f]+1;fa[y]=fa[x];pos[y]=pos[x];fa[x]=fa[p]=y;
		for(int i=0;i<M;i++)ch[y][i]=ch[x][i];
		while(f&&ch[f][c]==x)ch[f][c]=y,f=fa[f];
	}
	void f1(){
		for(int u=gt;u>=1;u--){
			anc[u][0]=fa[u];
			e[fa[u]].pb(u);
		}
		dfs(1);
		id[0]=1;
		for(int i=1;i<=n;i++){
			int c=S[i]-'a';
			id[i]=ch[id[i-1]][c];
		}
	}
	void dfs(int u){
		int &tmp=ans[u];tmp=n+1;
		for(int i=1;i<=20;i++){
			anc[u][i]=anc[anc[u][i-1]][i-1];
		}
		for(auto v:e[u]){
			dfs(v);
			tmp=min(tmp,ans[v]);
			if(u==1){continue;}
			if(s[u].size()>=s[v].size()){
				for(auto j:s[v]){
					auto it=s[u].insert(j).first;
					if(it!=s[u].begin()){
						--it;
						tmp=min(tmp,j-*it);
						++it;
					}
					if((++it)!=s[u].end()){
						tmp=min(tmp,*it-j);
					}
				}
			}
			else{
				for(auto j:s[u]){
					auto it=s[v].insert(j).first;
					if(it!=s[v].begin()){
						--it;
						tmp=min(tmp,j-*it);
						++it;
					}
					if((++it)!=s[v].end()){
						tmp=min(tmp,*it-j);
					}
				}
				s[u]=move(s[v]);
			}
		}
	}
}g;
void f1(){
	int Q;
	scanf("%d%d%s",&n,&Q,S+1);
	g.init2();
	for(int i=1;i<=n;i++){
		g.ins(S[i]-'a',i);
		s[g.lst].insert(i);
	}
	g.f1();
	for(int i=1;i<=Q;i++){
		int x,y;scanf("%d%d",&x,&y);
		int p=id[y],l=y-x+1;
		for(int i=20;i>=0;i--){
			int na=anc[p][i];
			if(na>1&&g.len[na]>=l){
				p=na;
			}
		}
		if(ans[p]<l){
			printf("Yes\n");
		}
		else{
			printf("No\n");
		}
	}
}
int main(){
	int t;scanf("%d",&t);
	while(t--){
		f1();
	}
	return 0;
}

question:

第一题: https://acm.hdu.edu.cn/showproblem.php?pid=708

thought:

将 n 个大小为2的整数次幂的数放到 m 个一定空间的分条内,问能否放入。

思路:
首先可以用贪心的思想,把最大的数据往剩余空间最大的分条内放,将数据从大到小排序,再用一个堆来存放所有分条。

#include<bits/stdc++.h>
using namespace std;

const int N = 100010;

int t,n,m,a[N];

int main()
{
    cin>>t;
    int x;

    while(t -- )
    {
        cin>>n>>m;
        priority_queue<int>heap;

        for(int i = 0; i < n; i ++ )
            cin>>a[i];
        for(int i = 0; i < m; i ++ )
        {
            cin>>x;
            heap.push(x);
        }

        sort(a,a + n,greater<int>());

        bool flag = true;

        for(int i = 0; i < n; i ++ )
        {
            if(heap.size() && heap.top() >= a[i])
            {
                int t = heap.top();
                heap.pop();
                if(t - a[i])
                    heap.push(t - a[i]);
            }
            else
            {
                flag = false;
                break;
            }
        }
        if(flag)
            cout<<"Yes"<<endl;
        else
            cout<<"No"<<endl;
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SUGA no sugar

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值