Pjudge #21695. 异或序列
首先有个sb\(O(n^3)\)dp,大概就是设\(dp_{i,j}\)表示最后一个是\(i\),前一个是\(j\)的方案数。
这样没啥前途,我们考虑发掘一点性质。
首先发现,对于一个长度为\(4\)的子段,不会出现两个连续三项不合法,因为如果这样那么第一个等于第四个,则不满足递增的要求。
这样我们可以简化我们的dp状态,设\(f_i\)为以\(i\)结尾的答案,则\(i\)可以转移到任意\(j\)作为下一个,但是要排除掉\((j,h)\)这样的二元组满足\(i\operatorname{xor}j=h\)且\(i<j<h\),要将\(f_h\)减去\(f_i\)。这样子可以优化到\(O(n^2)\)。
我们来观察两个转移,第一个转移可以记一个变量来帮助转移,第二个观察发现,\(h\)的位数要比\(j\)大,且\(h\)在\(j\)最高位为\(1\),则就是\(h\)存在的充要条件。
则可以为每一位维护一个前缀和,时间复杂度\(O(n\log n)\)
code:
#include<bits/stdc++.h>
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((m)*(x-1)+(y))
#define R(n) (rnd()%(n))
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using ll=long long;using db=double;using lb=long db;using ui=unsigned;using ull=unsigned ll;
using namespace std;const int N=1e6+5,M=N*4+5,K=1e5+5,mod=1e9+7,Mod=mod-1,INF=2e9+7;const db eps=1e-5;
int n,p,x,y,z;ll dp[N],Ans,f[N][20],Ts;
int main(){
freopen("1.in","r",stdin);
int i,j;scanf("%d%d",&n,&p);for(i=1;i<=n;i++){dp[i]=Ts+1;
for(j=0;j<20;j++) f[i][j]=(f[i-1][j]+f[i][j])%p,i>>j&1&&(dp[i]=(dp[i]+p-f[i][j])%p);
Ts=(dp[i]+Ts)%p;x=log2(i);f[1<<x+1][x]=(f[1<<x+1][x]+dp[i])%p;
}printf("%lld\n",Ts%p);
}