zoukankan      html  css  js  c++  java
  • 题解-ARC077F

    神仙字符串结论题。

    我们先进行一次操作变成一个 (SS) 串,然后考虑 (S) 的循环节 (G)

    1. (G)(S) 的整循环节

    那么这个串会变成 (SGSG)(SGGSGG),...,(SGGGG...SGGGG....),由于是无限长我们只需考虑前半部分即可。这个直接求就行。

    1. (G) 不是 (S) 的整循环节

    其实只是上一部分的扩展。

    还是只用考虑前半部分,而前半部分的情况是 (S_i=S_{i-1}+S_{i-2}),也就是 (S)(SG)(SGS)(SGSSG)(其实样例已经给了提示)。

    接下来我们来证明:

    该结论等价于证明 (SG) 的最小循环节为 (S),且不会出现 (G) 变成整循环节的情况。设 (SG=T)

    我们假设存在一个循环节 (p)(S) 更短,那么 (p) 也是 (S) 的循环节,所以 (T[i]=T[i-p]) 由于 (G)(S) 的前缀,所以 (T[i]=T[i-|S|]),又因为 (G) 是周期,所以 (i-pequiv i-|S|pmod |G|)(|p|equiv |S|pmod |G|),由于弱周期引理,(S) 有新的周期 (gcd(|p|,|G|)),所以 (p)(|G|) 的倍数,所以 (|S|mod |G|=0) 矛盾!

    于是我们直接暴力模拟即可。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn = 2000005;
    template <typename T>
    void read(T &x) {
    	T flag = 1;
    	char ch = getchar();
    	for (; !isdigit(ch); ch = getchar()) if (ch == '-') flag = -1;
    	for (x = 0; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
    	x *= flag;
    }
    char s[maxn];
    int nxt[maxn];
    ll l, r;
    int n, m;
    ll cnt[30], cntg[30], ans[30];
    ll f[maxn];
    ll cur[30], lst[30];
    void solve(ll x, ll v) {
    	if (x == 0) return;
    	if (x <= n) {
    		for (int i = 1; i <= x; i++) ans[s[i] - 'a'] += v;
    	} else {
    		x -= n;
    		for (int i = 0; i < 26; i++) ans[i] = ans[i] + v * (cnt[i] + cntg[i] * (x / m));
    		for (int i = 1; i <= x % m; i++) ans[s[i] - 'a'] += v;
    	}
    }
    void dfs(ll x, ll v) {
    	if (x <= 0) return;
    	if (x <= n) {
    		for (int i = 1; i <= x; i++) ans[s[i] - 'a'] += v;
    		return;
    	}
    	f[1] = n, f[2] = n + m;
    	int now = 2;
    	for (int i = 0; i < 26; i++) cur[i] = cnt[i] + cntg[i], lst[i] = cnt[i];
    	while (f[now] <= x) {
    		if (now > 2) {
    			for (int i = 0; i < 26; i++) {
    				ll tmp = cur[i];
    				cur[i] += lst[i];
    				lst[i] = tmp;
    			}
    		}
    		f[now + 1] = f[now] + f[now - 1];
    		now++;
    	}
    	if (now == 2) {
    		for (int i = 0; i < 26; i++) ans[i] += lst[i] * v;
    		dfs(x - f[now - 1], v);
    	} else {
    		for (int i = 0; i < 26; i++) ans[i] += cur[i] * v;
    		dfs(x - f[now - 1], v);
    	}
    }
    int main() {
    	scanf("%s", s + 1);
    	read(l); read(r);
    	n = strlen(s + 1);
    	for (int i = 2, j = 0; i <= n; i++) {
    		while (j && s[j + 1] != s[i]) j = nxt[j];
    		if (s[j + 1] == s[i]) j++;
    		nxt[i] = j;
    	}
    	int tmp = nxt[n];
    	while (tmp >= (n + 1) / 2) {
    		tmp = nxt[tmp];
    	}
    	n -= tmp;
    	for (int i = 1; i <= n; i++) cnt[s[i] - 'a']++;
    	m = n - nxt[n];
    	for (int i = 1; i <= m; i++) cntg[s[i] - 'a']++;
    	if (n % (n - nxt[n]) == 0) {
    		solve(r, 1); solve(l - 1, -1);
    		for (int i = 0; i < 26; i++) printf("%lld ", ans[i]);
    	} else {
    		dfs(r, 1); dfs(l - 1, -1);
    		for (int i = 0; i < 26; i++) printf("%lld ", ans[i]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    OpenCV教程(46) 快速特征检测
    OpenCV教程(45) harris角的检测(3)
    OpenCV教程(44) harris角的检测(2)
    OpenCV教程(43) harris角的检测(1)
    Andriod源码搜集
    OpenCV特征检测教程
    使用SGD(Stochastic Gradient Descent)进行大规模机器学习
    根据两点经纬度计算距离【转】
    转载]根据两点的经纬度求方位角和距离,等
    array
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/15106469.html
Copyright © 2011-2022 走看看