Codeforces 827E Rusty String

本文介绍了一种利用NTT/FFT技术解决特定字符串循环周期问题的方法。通过将字符串中的字符映射为数值,并运用快速傅里叶变换,作者提出了一种高效算法来找出所有可能的循环长度。

一万年没有写过题解了...这题idea是不错

题意

给你一个只由V/K/?组成的字符串,问这个字符串的循环长度可以是多少,其中表示既可以是V也可以是K。将所有可能的循环长度都输出。

想法

如果没有?,那就是next数组判断。而之所以可以用next数组判断,是因为假设循环长度为\(d\),那么将字符串向右滑动\(d\)位之后重合的部分一定完全相同。基于这个理论,这道题也可以这么想。
假设循环长度为\(d\),将字符串向右滑动\(d\)位,重合的部分中,如果\(a_{d+i} == b_{i}(0 \leq i \leq n-1)\),则\(d\)可以被记录到答案中。
如果把b数组翻转一下是不是就很像卷积了?但是怎么做乘法呢?
我一开始想如果相等就为1,即两个1相乘,最后加起来如果是\(n-d\)就说明有效。但是这样VK就要分开看啊,没有办法进行一个统一的判断。
然后idea就来了...

for (int i = 0; i < n; i++) {
    if (s[i] == 'V') a[i] = 1;
    else if (s[i] == 'K') b[n - i] = 1;
}

这样的话...如果匹配就是0,如果加起来就是0那么可行...妙啊!
然后跑ntt/fft就好了。数据里面好像卡了一发长度为1的ntt?特判一下就好了。

Code
#include <bits/stdc++.h>
#define N (1 << 20)
#define ll long long
#define pb push_back
using namespace std;
const ll M = 998244353;
const ll g = 3; 
ll Pow(ll a, ll n) {
   ll ret = 1;
   while (n) {
      if (n & 1) ret = ret * a % M;
      n >>= 1;
      a = a * a % M;
   }
   return ret;
}
void rader(ll y[], int len) {
   for (int i = 1, j = len / 2; i < len - 1; i++) {
      if (i < j) swap(y[i], y[j]);
      int k = len / 2;
      while (j >= k) {
         j -= k;
         k /= 2;
      }
      if (j < k) j += k;
   }
}
void ntt(ll y[], int len, int on) {
   rader(y, len);
   for (int h = 2; h <= len; h <<= 1) {
      ll wn = Pow(g, (M - 1) / h);
      if (on == -1) wn = Pow(wn, M - 2);
      for (int j = 0; j < len; j += h) {
         ll w = 1;
         for (int k = j; k < j + h / 2; k++) {
            ll u = y[k];
            ll t = w * y[k + h / 2] % M;
            y[k] = (u + t) % M;
            y[k + h / 2] = (u - t + M) % M;
            w = w * wn % M;
         }
      }
   }
   if (on == -1) {
      ll t = Pow(len, M - 2);
      for (int i = 0; i < len; i++)
     y[i] = y[i] * t % M;
   }
}
ll a[N], b[N];
int n, len;
char s[N];
int T;
bool ans[N]; 
vector <int> w; 
void init()
{
   w.clear();
   for (int i = 0; i <= len; i++) {
      a[i] = b[i] = ans[i] = 0;
   }
}
int main()
{
   cin >> T;
   while (T--) {
      scanf("%d%s", &n, s);
      if (n == 1) printf("1\n1");
      else {
         len = 1; 
         while (len <= n * 2) len <<= 1;
         init(); 
         for (int i = 0; i < n; i++) {
            if (s[i] == 'V') a[i] = 1;
            else if (s[i] == 'K') b[n - i] = 1;
         } 
         ntt(a, len, 1);
         ntt(b, len, 1);
         for (int i = 0; i <= len; i++)
            a[i] = (a[i] * b[i]) % M;
         ntt(a, len, -1);
         for (int i = 1; i <= n; i++)
            if (a[n - i] == 0 && a[n + i] == 0) ans[i] = true;
         for (int i = 1; i <= n; i++) {
            for (int j = i << 1; j <= n; j += i)
               ans[i] &= ans[j];
            if (ans[i]) w.pb(i);
         }
         cout << w.size() << endl;
         for (int i = 0; i < (int)w.size(); i++)
            printf("%d ", w[i]);
      }
      putchar('\n');
   }
   return 0; 
}

转载于:https://www.cnblogs.com/zkGaia/p/7160247.html

### Codeforces 887E Problem Solution and Discussion The problem **887E - The Great Game** on Codeforces involves a strategic game between two players who take turns to perform operations under specific rules. To tackle this challenge effectively, understanding both dynamic programming (DP) techniques and bitwise manipulation is crucial. #### Dynamic Programming Approach One effective method to approach this problem utilizes DP with memoization. By defining `dp[i][j]` as the optimal result when starting from state `(i,j)` where `i` represents current position and `j` indicates some status flag related to previous moves: ```cpp #include <bits/stdc++.h> using namespace std; const int MAXN = ...; // Define based on constraints int dp[MAXN][2]; // Function to calculate minimum steps using top-down DP int minSteps(int pos, bool prevMoveType) { if (pos >= N) return 0; if (dp[pos][prevMoveType] != -1) return dp[pos][prevMoveType]; int res = INT_MAX; // Try all possible next positions and update 'res' for (...) { /* Logic here */ } dp[pos][prevMoveType] = res; return res; } ``` This code snippet outlines how one might structure a solution involving recursive calls combined with caching results through an array named `dp`. #### Bitwise Operations Insight Another critical aspect lies within efficiently handling large integers via bitwise operators instead of arithmetic ones whenever applicable. This optimization can significantly reduce computation time especially given tight limits often found in competitive coding challenges like those hosted by platforms such as Codeforces[^1]. For detailed discussions about similar problems or more insights into solving strategies specifically tailored towards contest preparation, visiting forums dedicated to algorithmic contests would be beneficial. Websites associated directly with Codeforces offer rich resources including editorials written after each round which provide comprehensive explanations alongside alternative approaches taken by successful contestants during live events. --related questions-- 1. What are common pitfalls encountered while implementing dynamic programming solutions? 2. How does bit manipulation improve performance in algorithms dealing with integer values? 3. Can you recommend any online communities focused on discussing competitive programming tactics? 4. Are there particular patterns that frequently appear across different levels of difficulty within Codeforces contests?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值