专栏文章
P11410 闪耀之塔 题解
P11410题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mioadxou
- 此快照首次捕获于
- 2025/12/02 15:58 3 个月前
- 此快照最后确认于
- 2025/12/02 15:58 3 个月前
不错的题,这里给一个矩阵优化 DP 的做法。
首先我们看每一个点的贡献,容易发现第一层的点贡献是 ,第二层是 ,依次类推。
所以,第一层放 ,第二层放 和 ,第 层放 到 的数最优。
然后关注我们的查询。
我们发现,这个点的深度就是 (我们定义第一个点的深度为 ),所以答案和这个点是什么不重要,重要的是它的深度。
那么,我们相当于选择一个 层的满二叉树进行放数。
设 表示选择一个 层的满二叉树进行放数,不难得到递推式:。
注意到 也是可以递推的,预处理之后,你就拿到了 分。
接下来怎么做?
我们现在不得不定义一些东西了。
我们记 表示 ,递推式:
我们记 表示 ,递推式:。
我们记 表示 ,递推式:,其中 表示 的逆元。
那么 可以表示成:。
上述的递推式可以放在一个矩阵中进行转移,转移式子为:
时间复杂度:,其中 是矩阵大小,你可以认为 。
代码:
CPP#include<bits/stdc++.h>
#define int long long
using namespace std;
const int M=5;
const int mod=1e9+7;
struct matrix{
int n,a[M][M];
matrix(int _n){
n=_n;
memset(a,0,sizeof(a));
}
void print(){
for(int i=0;i<n;i++,cout<<"\n")
for(int j=0;j<n;j++)
cout<<a[i][j]<<" ";
cout<<"\n";
return;
}
friend matrix operator * (matrix a,matrix b){
int n=a.n;
matrix c(n);
for(int k=0;k<n;k++)
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%mod;
return c;
}
friend matrix operator ^ (matrix a,int b){
int n=a.n;
matrix z(n);
for(int i=0;i<n;i++)z.a[i][i]=1;
while(b){
if(b&1)z=z*a;
a=a*a;
b>>=1;
}
return z;
}
};
int ksm(int a,int b){
int z=1;
while(b){
if(b&1)z=z*a%mod;
a=a*a%mod;
b>>=1;
}
return z;
}
int inv(int x){
return ksm(x,mod-2);
}
const int inv2=(mod+1)/2;
int n,k,q;
string s;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>q;
matrix A(5),B(5),ans(5);
B.a[0][0]=0;
B.a[1][0]=0;
B.a[2][0]=ksm(2,n);
B.a[3][0]=1;
B.a[4][0]=1;
A.a[0][0]=2;A.a[0][1]=-1;A.a[0][2]=1;A.a[0][3]=0;A.a[0][4]=-1;
A.a[1][0]=0;A.a[1][1]=1;A.a[1][2]=0;A.a[1][3]=1;A.a[1][4]=0;
A.a[2][0]=0;A.a[2][1]=0;A.a[2][2]=inv2;A.a[2][3]=0;A.a[2][4]=0;
A.a[3][0]=0;A.a[3][1]=0;A.a[3][2]=0;A.a[3][3]=4;A.a[3][4]=0;
A.a[4][0]=0;A.a[4][1]=0;A.a[4][2]=0;A.a[4][3]=0;A.a[4][4]=1;
while(q--){
cin>>k;
cin>>s;
ans=A;
ans=ans^(n-k+1);
ans=ans*B;
// ans.print();
cout<<(ans.a[0][0]%mod+mod)%mod<<"\n";
}
return 0;
}
/*
*/
如果还有不理解的,可以看一下 分暴力代码:
CPP#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=3000010;
const int mod=1e9+7;
const int INF=0x3f3f3f3f3f3f3f3f;
int n,q;
int dp[N];
int sum[N];
int ksm(int a,int b){
int z=1;
while(b){
if(b&1)z=z*a%mod;
a=a*a%mod;
b>>=1;
}
return z;
}
int inv(int x){
return ksm(x,mod-2);
}
int k;
string s;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>q;
for(int i=1;i<=n;i++){
dp[i]=2*dp[i-1]-sum[i-1]+ksm(2,n-i+1)-1;
dp[i]=(dp[i]%mod+mod)%mod;
sum[i]=sum[i-1]+ksm(2,i-1)*ksm(2,i-1)%mod;
sum[i]%=mod;
}
while(q--){
cin>>k;
cin>>s;
cout<<dp[n-k+1]<<"\n";
}
return 0;
}
/*
*/
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...