• 20210527模拟赛总结


    似乎今天的比较简单?(不是)

    T1

    原题,非常的简单,直接差分一下然后双指针搞一下就好了。

    T2

    看两个字符串,一定是串A的头和串B的尾相连,而A的前缀与B的后缀则是回文串的前后缀。

    可以发现对于选出的A前缀a,B后缀b。首先将b翻转,发现两个串中较短者是另一个的前缀,这个性质显然。除此之外,去掉重复部分剩下的一定是一个回文串。

    我们可以枚举较短串的长度,然后看能接上多少个回文串来统计答案。可以先使用manacher求出每个字符开始有多少个回文串的差分数组,然后再前缀和求出原数组,然后再来一遍前缀和便于求区间和即可。

    并不是很轻松,但也不算是很难。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    #define int long long
    
    using namespace std;
    
    int read()
    {
    	int a = 0,x = 1;char ch = getchar();
    	while(ch > '9' || ch < '0') {if(ch == '-') x = -1;ch = getchar();}
    	while(ch >= '0' && ch <= '9') {a = a*10 + ch-'0';ch = getchar();}
    	return a*x;
    }
    const int N=1e6+7,base=131,mod=19260817;
    char s1[N],s2[N],tmp[N];
    int n1,n2,a1[N],a2[N],r[N],m,f[N],hash1[N],hash2[N];
    
    void init(char *s,int n,int *a)
    {
    	tmp[0] = '-';int len = 0;
    	for(int i = 1;i <= n;i ++) {
    		tmp[++len] = s[i];
    		tmp[++len] = '-';
    	}
    	int p = 0,mx = 0;
    	for(int i = 1;i <= len;i ++) {
    		// printf("%d ",i);
    		if(mx > i) r[i] = min(mx-i+1,r[2*p-i]);
    		else r[i] = 0;
    		while(i+r[i] <= len && i-r[i] >= 0) {
    			if(tmp[i+r[i]] == tmp[i-r[i]]) r[i] ++;
    			else break;
    		}
    		if(i+r[i]-1 > mx) mx = i+r[i]-1,p = i;
    	}
    	// printf("%s
    ",tmp+1);
    	// for(int i = 1;i <= len;i ++) printf("%d",r[i]);puts("");
    	for(int i = 1;i < len;i ++) {
    		if(i&1) {
    			a[(i-r[i]+1)/2+1] ++;
    			a[(i+1)/2+1] --;
    			// printf("%d %d
    ",(i-r[i]+1)/2+1,(i+1)/2);
    		} else {
    			a[(i-r[i])/2+2] ++;
    			a[i/2+1] --;
    			// printf("%d %d
    ",(i-r[i])/2+2,(i)/2);
    		}
    	}
    	for(int i = 1;i <= n+1;i ++) a[i] = a[i] + a[i-1];//printf("%d ",a[i]);puts("");
    	for(int i = 1;i <= n+1;i ++) a[i] = a[i-1] + a[i];
    }
    
    bool check(int l1,int r1,int l2,int r2)
    {
    	return ((hash1[r1] - f[r1-l1+1]*hash1[l1-1]%mod)%mod+mod)%mod == ((hash2[r2] - f[r2-l2+1]*hash2[l2-1]%mod)%mod+mod)%mod;
    }
    
    signed main()
    {
    	freopen("palindrome.in","r",stdin);
    	freopen("palindrome.out","w",stdout);
    	scanf("%s",s1+1);
    	scanf("%s %s",s1+1,s2+1);
    	n1 = strlen(s1+1),n2 = strlen(s2+1);
    	reverse(s2+1,s2+1+n2);f[0] = 1;
    	for(int i = 1;i <= n1;i ++) hash1[i] = (hash1[i-1]*base + s1[i])%mod,f[i] = f[i-1]*base%mod;
    	for(int i = 1;i <= n2;i ++) hash2[i] = (hash2[i-1]*base + s2[i])%mod;
    	init(s1,n1,a1);init(s2,n2,a2);m = read();
    	// for(int i = 1;i <= n1;i ++) printf("%d ",a1[i]-a1[i-1]);puts("");
    	// for(int i = 1;i <= n2;i ++) printf("%d ",a2[i]-a2[i-1]);puts("");
    	for(int i = 1;i <= m;i ++) {
    		// printf("%d %d
    ",p,q);
    		// puts("!");
    		int p = read(),q = read();
    		// printf("%s
    %s
    ",s1+p-1,s2+q-1);
    		int l = 0,r = min(n1-p+1,n2-q+1),mid;
    		while(l<r) {
    			mid = l+r+1>>1;
    			if(check(p,p+mid-1,q,q+mid-1)) l = mid;
    			else r = mid-1;
    		}
    		int ans = 0;//printf("%d ",l);
    		ans = (a1[p+l] - a1[p]) + (a2[q+l] - a2[q]);
    		// printf("%lld - %lld + %lld - %lld 
    ",a1[p+l],a1[p],a2[q+l],a2[q]);
    		printf("%lld
    ",ans + l);
    	}
    	return 0;
    }
    

    另:模拟的时候第一想法居然是SA+st表求lcp,然后manacher求回文串再上线段树修改查询……直接爆炸。

    T3

    并不会,时间不太够了。一开始以为想出来了个nk的做法,写着写着发现复杂度和正确性都假了……自闭。

  • 相关阅读:
    阿迪亚香提:顿悟
    生活就像练习-整合式探究
    [Web API] Web API 2 深入系列(1) 路由
    Sublime Text 2
    整合练习:信息过剩时代的止痛药
    win (NT6.1+) server版的:【2个远程桌面用户(单会话)】升级为终端服务器【多用户(多会话)】
    win (NT6.1+) 非server版的:【单个远程桌面用户(单会话)】远程桌面多开【多用户(单会话)】
    win7:【单个远程桌面用户(单会话)】远程桌面多开【多用户(单会话)】
    win 2003:【2个 远程桌面用户({允许同一个用户最多2个会话})】升级为终端服务【多用户(多会话)】
    win xp:【单用户(单会话)】远程桌面多开【多用户(单会话)】
  • 原文地址:https://www.cnblogs.com/nao-nao/p/14819044.html
Copyright © 2020-2023  润新知