250
Description
从一个字符串中找一字典序最大的字串
Solution
从左至右贪心即可
500:
Description
有一个序列,每次可以将一个数-1需要花费1的代价,问最后使得序列满足 2ai≤ai−1+ai+1
Solution
因为满足 ai−1−ai≥ai−ai+1 `,也就是说序列相邻两项差是递减的,所以每当不满足条件时暴力调整` ai ,直到不需要调整为止。想想极限数据调整次数即可直到复杂度是靠谱的。
1000
Description
求符合以下条件的序列个数
- 1:长度为K
- 2:每个元素大小不超过L
- 3:每个数都是质数
- 4:所有数异或和为0
K≤109,L≤5×104
Solution
基本的递推方程很容易列出来
fi,j表示前i个数异或和为j的方案数
则:
fi,x⊕y=∑0≤x,y≤216fi−1,x×f1,y
f1,y=1当且仅当y为质数且y≤L
这样暴力递推显然是
O(KL2)的,i为偶数时分治一下可以做到O(L2log2K)的
,复杂度还是不行
然后我们可以想到把这个东西搞成类似于FFT的东西。
设向量a,b,c,定义向量之间的运算
$,c=a$b
ci⊕j=∑ai×bj,做变换tf,使得tf(a$b)=tf(a)×tf(b),逆变换dft(tf(x))=x
设a向量,ai表示i堆石子异或和为0∼216的方案数,a1在素数位置处为1,其他位置为0
这样我们只需要用log2K的时间算出tf(a1)K,在做逆变换得到aK即为答案
观察tf和dtf的性质,当只有一个元素时,tf(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)=(a−b,a+b)
tf(X)×tf(Y)=(a−b,a+b)×(c−d,c+d)
则
=((a−b)×(c−d),(a+b)×(c+d))
=(ac+bd−ad−bc,ac+bd+ad+bc)
=tf(ac+bd,ac−bd)
=tf((a,b)$(c,d))
=tf(X$Y)
有A,B两向量,用归纳法可证明出tf(A+B)=tf(A)+tf(B)
如果我们将X向量分成两段等长的向量X1,X2
我们归纳一下会发现tf(X1,X2)=(tf(X1)−tf(X2),tf(X1)+tf(X2))
(X1−X2)i=X1i−X2i
(X1+X2)i=X1i+X2i
将A分为A1,A2,B分为B1,B2
则依旧可以归纳证出tf((A1,A2)$(B1,B2))=tf(A1,A2)×tf(B1,B2)
即对任意向量A,B,tf(A$B)=tf(A)×tf(B)
说明当有两个元素时,tf(a,b)=(a−b,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];
}
}