模拟测试49
这次考试题还是蛮好的,只是人很水啊
T1
考场思路:
1.每次询问离线出来,再对于每一个k进行操作,$O(klnk)$枚举区间,再利用主席树查前驱,期望时间复杂度$O(nlogn^2)$但可以被卡到$O(n^2logn)$(对于k极小的询问),如果优化就把k极小的询问预处理?不可实现弃辽
2.分块,不会处理每一块的答案,死了
所以正解还是分块,考虑预处理每一块答案。
对于一个k来说,答案是$max_{i=0}^{n/k}max_{j=i*k}^{i*k+k-1} \{a[j]-i*k\}$,开一个桶维护每一块内的元素,扫一边搞出<=每个数的数直接处理即可。复杂度为$O(n^2lnn/S+m*S)$当S取$\sqrt{nlogn}$的时候最小为$O(n\sqrt{nlogn})$
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cmath> 3 #include<iostream> 4 #define N 100001 5 #define sN 105 6 using namespace std; 7 inline int _max(int a,int b){return a>b?a:b;} 8 int bl[N+5],ans[sN][N+5],t[N+5],tl[N+5],tot,L[sN],a[N+5]; 9 inline int read() 10 { 11 int x=0,f=1;char c=getchar(); 12 while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();} 13 while(c>='0'&&c<='9')x=x*10+c-48,c=getchar(); 14 return x*f; 15 } 16 inline void pre() 17 { 18 int now; 19 for(int i=1;i<=tot;i++) 20 { 21 now=L[i]; 22 while(bl[now]==i)t[a[now]]++,tl[a[now]]=a[now],now++; 23 for(int j=1;j<=N;j++)if(!t[j])tl[j]=tl[j-1];now=L[i]; 24 for(int j=2;j<=N;j++) 25 { 26 for(int k=j-1;k<=N;k+=j) 27 ans[i][j]=_max(ans[i][j],(tl[k]%j)); 28 ans[i][j]=_max(ans[i][j],(tl[N]%j)); 29 } 30 while(bl[now]==i)t[a[now]]--,tl[a[now]]=0,now++; 31 } 32 } 33 inline int query(int l,int r,int k) 34 { 35 int mx=0; 36 if(bl[l]==bl[r]) 37 { 38 for(int i=l;i<=r;i++)mx=_max(mx,a[i]%k); 39 return mx; 40 } 41 for(int i=l;bl[i]==bl[l];i++)mx=_max(mx,a[i]%k); 42 for(int i=bl[l]+1;i<bl[r];i++)mx=_max(mx,ans[i][k]); 43 for(int i=r;bl[i]==bl[r];i--)mx=_max(mx,a[i]%k); 44 return mx; 45 } 46 int main() 47 { 48 int n=read(),m=read(); 49 int t=sqrt(n*20)+1; 50 for(int i=1;i<=n;i++) 51 { 52 bl[i]=(i-1)/t+1;//printf("%d\n",bl[i]); 53 if(bl[i]!=bl[i-1])L[bl[i]]=i; 54 a[i]=read(); 55 }tot=bl[n];pre(); 56 while(m--) 57 { 58 int l=read(),r=read(),k=read(); 59 printf("%d\n",query(l,r,k)); 60 } 61 return 0; 62 }
T2
n^2思路很简单,但是会被卡空间。
所以换个角度,按x排序。
实际上就是找不断往中间收缩的方案数(感性理解)
考虑处理出前i-1个如何弄第i个,设dp[i][0/1]表示以i为起点往左/右走的方案数
如果i是起点,那么给i加上前面比它小的往右撇的方案即可
如果不是,那么i一定是第二个点,枚举起点和第三个点,给起点加上第三个点的贡献。
得出转移方程:
dp[i][0]+=dp[j][1] (j<i&&y[j]<y[i])
dp[j][1]+=dp[z][1] (j<i&&z>j&&z<i&&y[z]<y[j]&&y[j]<y[i])
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<algorithm> 3 #define FH_SB 6005 4 using namespace std; 5 const int mod=1e9+7; 6 int dp[FH_SB][2],s[FH_SB]; 7 struct node{ 8 int fh,sb; 9 inline void init(){scanf("%d%d",&fh,&sb);} 10 friend bool operator <(const node a,const node b){ return a.fh<b.fh;} 11 }a[FH_SB]; 12 int main() 13 { 14 int n,ans=0;scanf("%d",&n); 15 for(int i=1;i<=n;i++)a[i].init(); 16 sort(a+1,a+n+1); 17 for(int i=1;i<=n;i++) 18 { 19 s[i]=1;dp[i][0]++;dp[i][1]++; 20 for(int j=i-1;j;j--) s[j]=(s[j+1]+dp[j][1]*(a[j].sb<a[i].sb))%mod; 21 for(int j=1;j<i;j++) 22 { 23 if(a[j].sb<a[i].sb)(dp[i][0]+=dp[j][1])%=mod; 24 else (dp[j][1]+=s[j+1])%=mod; 25 } 26 } 27 for(int i=1;i<=n;i++)(ans+=(dp[i][0]+dp[i][1])%mod)%=mod; 28 printf("%d\n",ans-n); 29 }
T3不会,咕了。