srm 518(有FWT的题QvQ)

250

Description

从一个字符串中找一字典序最大的字串

Solution

从左至右贪心即可

500:

Description

有一个序列,每次可以将一个数-1需要花费1的代价,问最后使得序列满足2aiai1+ai+1

Solution

因为满足ai1aiaiai+1 `,也就是说序列相邻两项差是递减的,所以每当不满足条件时暴力调整`ai ,直到不需要调整为止。想想极限数据调整次数即可直到复杂度是靠谱的。

1000

Description

求符合以下条件的序列个数

  • 1:长度为K
  • 2:每个元素大小不超过L
  • 3:每个数都是质数
  • 4:所有数异或和为0
    K109,L5×104

Solution

基本的递推方程很容易列出来fi,jij
则:fi,xy=0x,y216fi1,x×f1,y
f1,y=1yyL
这样暴力递推显然是O(KL2),iO(L2log2K) ,复杂度还是不行
然后我们可以想到把这个东西搞成类似于FFT的东西。
设向量a,b,c,定义向量之间的运算$,c=a$b
cij=ai×bj,tf,使tf(a$b)=tf(a)×tf(b),dft(tf(x))=x
aaii0216a110
log2Ktf(a1)K,aK
tfdtftf(x)=dtf(x)=x
当有两个元素
X=(a,b),Y=(c,d)
Z=X$Y
Z0=X0×Y0+X1×Y1=ac+bd
Z1=X0×Y1+X1×Y0=ad+bc
tf(a,b)=(ab,a+b)
tf(X)×tf(Y)=(ab,a+b)×(cd,c+d)
=((ab)×(cd),(a+b)×(c+d))
=(ac+bdadbc,ac+bd+ad+bc)
=tf(ac+bd,acbd)
=tf((a,b)$(c,d))
=tf(X$Y)
ABtf(A+B)=tf(A)+tf(B)
XX1,X2
tf(X1,X2)=(tf(X1)tf(X2),tf(X1)+tf(X2))

(X1X2)i=X1iX2i
(X1+X2)i=X1i+X2i
AA1,A2,BB1,B2
tf((A1,A2)$(B1,B2))=tf(A1,A2)×tf(B1,B2)
ABtf(A$B)=tf(A)×tf(B)
,tf(a,b)=(ab,a+b)
然后我们就可以用tf(X1,X2)=(tf(X1)tf(X2),tf(X1)+tf(X2))
tf(a1)K,aK

还有不明白的可以看http://apps.topcoder.com/wiki/display/tc/SRM+518

Code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1<<16,M=1000000007;
ll a[N],inv2;
ll P(ll x,ll y){
    ll tmp=1ll;
    for(;y;y>>=1){
        if(y&1) tmp=tmp*x%M;
        x=x*x%M;
    }
    return tmp;
}
void trans(int l,int r){
    if(l==r-1)  return ;
    int len=(r-l)/2;
    int mid=l+len;
    trans(l,mid),trans(mid,r);
    for(int i=l;i<mid;++i){
        ll x1=(a[i]-a[i+len]+M)%M,x2=(a[i]+a[i+len])%M;
        a[i]=x1,a[i+len]=x2;
    }
}
void reverse(int l,int r){
    if(r-l==1)  return ;
    int len=(r-l)/2;
    int mid=l+len;
    for(int i=l;i<mid;++i){
        ll x1=a[i],x2=a[i+len];
        a[i]=(x1+x2)*inv2%M;
        a[i+len]=(x2-x1)*inv2%M;
    }
    reverse(l,mid),reverse(mid,r);
}
class Nim{
        public:
        int count(int K, int L){
            inv2=P(2,M-2);
            for(int i=2;i<=L;++i)
                if(!a[i])
                    for(int j=i+i;j<=L;j+=i)    a[j]=1;
            for(int i=2;i<=L;++i)   a[i]^=1;
            int Log=1;
            while(Log<=L)   Log<<=1;
            trans(0,Log);
            for(int i=0;i<Log;++i)  a[i]=P(a[i],K);
            reverse(0,Log);
            return a[0];
        }
}

Code链接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章