Kattis:K-Inversions

探讨了如何通过快速傅立叶变换(FFT)解决 K-Inversions 问题,该问题要求找出字符串中特定形式的倒置对数量。文章提供了一种创新的方法,将问题转化为多项式乘法,并给出了具体的实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

K-Inversions

Problem Description

You are given a string s consisting only of upper case letters A and B. For an integer k, a pair of indices i and j (1 ≤ i < j ≤ n) is called a k-inversion if and only if s[i] = B, s[j] = A and j − i = k.
 
Consider the string BABA. It has two 1-inversions and one 3-inversion. It has no 2-inversions.

For each k between 1 and n − 1 (inclusive), print the number of k-inversions in the string s. 

Input


    
    
Each input will consist of a single test case. Note that your program may be run multiple times on different inputs. The input will consist of a single line with a string s, which consists of only upper case As and Bs. The string s will be between 1 and 1,000,000 characters long. There will be no spaces

Output


    
    
Output n − 1 lines, each with a single integer. The first line’s integer should be the number of 1-inversions, the second should be the number of 2-inversions, and so on.

SampleInput

BABA

Sample Output

2
0
1 

来自kattis可以交题

Solve:

这个题就是求对于每个x,有多少AB之间相差x(A 在 B后面)

暴力的话,可以枚举每一个A和每一个B,求两者之间的距离为x,ans[x]++,但是这样肯定会超时的

那么想想多项式乘法,假如有两个多项式,那么他们的每一项系数都要互相乘,相乘时候具有相同的指数的系数加起来,那么他们的指数也是相加的

而这个题,把每个A的下标看成第一个式子的指数,系数都为1,B的下标看成第二个式子的指数,系数为1,那么这里是,指数相减之后相同的系数相乘求和

醉了,描述不清

那么我已经有了一个串比如BABA,定义两个数组

那么从左向右,如果扫到了A那么第一个数组相应的值为1

如果扫到了B,那么第二个数组倒着相应的值为0

所以第一个数组为0101

第二个数组为0101,把这两个串看成十进制的数字

那么这样的话,如果某个B出现在i位置上,A出现在j位置上,那么这两个位置对应的数组表示分别为1*10i,1*10n-j-1,那么这两位相乘之后得到的值为10n-j-1+i =10x,那么j-i=x+1-n也就是j和i之间相差几个,那么两个数字相乘就得到了所有的x

其中因为求的是相差1~n的有几个 ,所以1<=x-1+n<=n  ===>  0<=x<=n-2

所以应该输出最低位的n-1个,就是答案的(n~2n-1)位

所以就用FFT。。。。。。。

代码:

//https://open.kattis.com/problems/kinversions.cpp
#include 
   
   
    
    
using namespace std;

#define sz(v) ((int)(v).size())
#define all(v) (v).begin(),(v).end()
typedef complex
    
    
     
      base;

void fft(vector 
     
      &a, bool invert)
{
    int n = a.size();
    for (int i=1,j=0; i
     
     
      
      > 1;
        for (; j>=bit; bit>>=1) j -= bit;
        j += bit;
        if (i < j) swap(a[i],a[j]);
    }
    for (int len=2; len<=n; len<<=1)
    {
        double ang = 2*M_PI/len*(invert?-1:1);
        base wlen(cos(ang),sin(ang));
        for (int i=0; i
      
      
       
        &a,const vector
       
       
         &b,vector 
        
          &res) { vector 
          fa(a.begin(),a.end()), fb(b.begin(),b.end()); int n = 1; while (n < max(a.size(),b.size())) n <<= 1; n <<= 1; fa.resize(n); fb.resize(n); fft(fa,false); fft(fb,false); for (int i=0; i 
         
           0?0.5:-0.5)); } char t[1000001]; int main() { // freopen("in.txt","r",stdin); vector 
          
            a, b, r; int i, n; scanf("%s", t); for (n = 0; t[n]; n++); a.resize(n); b.resize(n); for (i = 0; i < n; i++) { if (t[i] == 'A') a[i] = 1; else b[n - i - 1] = 1; } multiply(a, b, r); for (i = 0; i < n * 2 - 1; i++) printf("%d\n", r[i]); } 
           
          
         
       
      
      
     
     
    
    
   
   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值