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鏈接

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