刷题记录_2024寒假2/19~2/21
P4287 [SHOI2011] 双倍回文
考虑马拉车,但是我不会马拉车
怎么办,考虑PAM
我们在记录一般的fail之外再记录一个trans指针指向小于等于当前节点长度一半的最长回文后缀
然后枚举每个节点
#include<bits/stdc++.h>
using namespace std;
char s[2000001];
int len[2000001],trans[2000001],n,num[2000001],fail[2000001],last,cur,pos,trie[2000001][26],tot=1;
int getf(int x,int i)
{
while(i-len[x]-1<0||s[i-len[x]-1]!=s[i])x=fail[x];
return x;
}
int main()
{
cin>>n;
scanf("%s",s);
fail[0]=1;len[1]=-1;
for(int i=0;i<n;i++){
pos=getf(cur,i);
if(!trie[pos][s[i]-'a']){
fail[++tot]=trie[ getf(fail[pos],i)][s[i]-'a'];
trie[pos][s[i]-'a']=tot;
len[tot]=len[pos]+2;
num[tot]=num[fail[tot]]+1;
if(len[tot]<=2) trans[tot]=fail[tot];
else{
int tmp=trans[cur];
while(s[i-len[tmp]-1]!=s[i]||((len[tmp]+2)<<1)>len[tot]) tmp=fail[tmp];
trans[tot]=trie[tmp][s[i]-'a'];
}
}
cur=trie[pos][s[i]-'a'];
}
int ans=0;
for(int i=2;i<=tot;i++)
if(((len[trans[i]]<<1)==len[i]&&len[trans[i]]%2==0))
ans=std::max(ans,len[i]);
printf("%d\n",ans);
return 0;
}
暴力枚举每个节点用trans判断
CF1895F Fancy Arrays
妙妙数数题
考虑容斥可以做掉第一个限制,然后就可以dp了
dp好慢,注意到可以写出转移矩阵,然后快速幂搞一发
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7;
int T,ans,b;
int n,x,k;
struct node{
int dp[41][41];
node operator*(const node &A)const{
node sum;
for(int i=0;i<x;++i)
for(int j=0;j<x;++j)
for(int k=0;k<x;++k)
sum.dp[i][j]=(sum.dp[i][j]+dp[i][k]*A.dp[k][j])%mod;
return sum;
}
}a,res;
int qpow(int a,int b){
int sum=1;
while(b){
if(b&1)sum*=a,sum%=mod;
a*=a,a%=mod;
b>>=1;
}
return sum;
}
signed main(){
std::ios::sync_with_stdio(false);
cin>>T;
while(T--){
cin>>n>>x>>k;
ans=qpow(2*k+1,n-1)*(x+k)%mod;
for(int i=0;i<x;++i)
for(int j=0;j<x;++j)
a.dp[i][j]=(abs(i-j)<=k);
res=node();
for(int i=0;i<x;++i)
res.dp[0][i]=1;
b=n-1;
while(b){
if(b&1)res=res*a;
a=a*a;
b>>=1;
}
for(int i=0;i<x;++i)
ans=(ans-res.dp[0][i]+mod)%mod;
cout<<ans<<"\n";
}
return 0;
}
P7453 [THUSCH2017] 大魔法师
经典的矩阵乘法线段树
每个节点存向量
给出每个操作的变换矩阵
然后可以码了
然后寄了
稍微卡常,矩阵乘法循环展开,取模用一定减法代替
#include<bits/stdc++.h>
#define ls (now<<1)
#define rs (now<<1|1)
using namespace std;
const int mod=998244353;
const int N=3e5+5;
int n,m;
int add(int x) {return x > mod ? x - mod : x;}
struct matrix{
int num[4][4];
matrix() {memset(num, 0, sizeof(num));}
inline void clear() {memset(num, 0, sizeof(num));}
inline void init() {num[0][0] = num[1][1] = num[2][2] = num[3][3] = 1;}//对角线1
matrix(const int a[][4]){
for(int i = 0; i < 4; ++i)
for(int j = 0; j < 4; ++j)
num[i][j] = a[i][j];
}
matrix operator + (const matrix &b) const{
matrix r;
for(int i = 0; i < 4; ++i)
for(int j = 0; j < 4; ++j)
r.num[i][j] = (1ll * num[i][j] + b.num[i][j]) % mod;
return r;
}
matrix operator * (const matrix &b) const{
matrix r;
r.clear();
for(int i = 0; i < 4; ++i)
for(int j = 0; j < 4; ++j){
r.num[i][j] = add(r.num[i][j] + 1ll * num[i][0] * b.num[0][j]%mod);
r.num[i][j] = add(r.num[i][j] + 1ll * num[i][1] * b.num[1][j]%mod);
r.num[i][j] = add(r.num[i][j] + 1ll * num[i][2] * b.num[2][j]%mod);
r.num[i][j] = add(r.num[i][j] + 1ll * num[i][3] * b.num[3][j]%mod);
// for(int k = 0; k < 4; k++) {
// r.num[i][j] = (r.num[i][j] + 1ll * num[i][k] * b.num[k][j] % mod) % mod;
// }
}
return r;
}
}a[N], A[4], B[4];
matrix tr[N<<2],tag[N<<2];
void pushup(int now){
tr[now]=tr[ls]+tr[rs];
}
void pushdown(int now){
tr[ls]=tag[now]*tr[ls];
tr[rs]=tag[now]*tr[rs];
tag[ls]=tag[now]*tag[ls];
tag[rs]=tag[now]*tag[rs];
tag[now].clear(),tag[now].init();
}
void build(int now,int l,int r){
tag[now].init();
if(l==r){
tr[now]=a[l];
return;
}
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
pushup(now);
}
void upd(int now,int l,int r,int L,int R,matrix k){
if(L<=l and r<=R){
tr[now]=k*tr[now];
tag[now]=k*tag[now];
return;
}
pushdown(now);
int mid=(l+r)>>1;
if(L<=mid) upd(ls,l,mid,L,R,k);
if(R>mid) upd(rs,mid+1,r,L,R,k);
pushup(now);
}
matrix query(int now,int l,int r,int L,int R){
if(L<=l and r<=R) return tr[now];
pushdown(now);
int mid=(l+r)>>1;
matrix res;res.clear();
if(L<=mid) res=res+query(ls,l,mid,L,R);
if(R>mid) res=res+query(rs,mid+1,r,L,R);
return res;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
A[0].init(),A[1].init(),A[2].init();
B[0].init(),B[1].init(),B[2].init();
A[0].num[0][1]=A[1].num[1][2]=A[2].num[2][0]=1;
B[2].num[2][2]=0;
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i].num[0][0]>>a[i].num[1][0]>>a[i].num[2][0],a[i].num[3][0]=1;
build(1,1,n);
cin>>m;
while(m--){
int opt,l,r,v;
cin>>opt>>l>>r;
if(opt<=3) upd(1,1,n,l,r,A[opt-1]);
else if(opt<=6){
cin>>v;
B[0].num[0][3]=B[1].num[1][1]=B[2].num[2][3]=v;
upd(1,1,n,l,r,B[opt-4]);
}
else{
matrix ans=query(1,1,n,l,r);
cout<<ans.num[0][0]<<" "<<ans.num[1][0]<<" "<<ans.num[2][0]<<"\n";
}
// cout << tr[1].num[0][0] << '\n';
}
}
P2522 [HAOI2011] Problem b
来点莫反
我们先考虑 P3455 [POI2007] ZAP-Queries
也就是给出 \(a,b,d\),求满足 \(1 \leq x \leq a\),\(1 \leq y \leq b\),且 \(\gcd(x,y)=k\) 的二元组 \((x,y)\) 的数量。
也就是 \(\large \sum\limits_{i=1}^{n} \sum\limits_{j=1}^{m} [gcd(i,j)=k]\)
简单思考我们能发现这个式子等价于 \(\large \sum\limits_{i=1}^{n/k} \sum\limits_{j=1}^{m/k} [\gcd(i,j)=1]\) (\(n/k,m/k\)下取整)
我们集中注意力回想一下怎么莫反于是这个式子变成了 \(\large \sum\limits_{i=1}^{n/k} \sum\limits_{j=1}^{m/k} \sum\limits_{d|\gcd(i,j)} \mu(d)\)
然后 \(\large \sum\limits_{i=1}^{n/k} \sum\limits_{j=1}^{m/k} \sum\limits_{d|i,d|j} \mu(d)\)
\(n\to n/k,m\to m/k\)
\(=\large \sum\limits_{d=1}^{\min(n,m)}\mu(d)\sum\limits_{d|i}^{n}\sum\limits_{d|j}^{m} 1\)
然后后面这一坨可以直接做掉
\(=\large \sum\limits_{d=1}^{\min(n,m)}\mu(d)\lfloor\dfrac{n}{d}\rfloor \lfloor \dfrac{m}{d} \rfloor\)
预处理一下 \(\mu\) 的前缀和然后数论分块做掉了
容斥一下就是这道题了
这道题有三倍经验)
#include<bits/stdc++.h>
using namespace std;
const int N=5e4+5;
typedef long long ll;
int T,k;
int cnt,p[N],mu[N],flg[N],sum[N];
void PRE(){
flg[1]=mu[1]=1;
for(int i=2;i<=N;i++){
if(!flg[i]) p[++cnt]=i,mu[i]=-1;
for(int j=1;j<=cnt and i*p[j]<=N;j++){
flg[i*p[j]]=1;
if(!(i%p[j])){
mu[i*p[j]]=0;break;
}
mu[i*p[j]]=-mu[i];
}
}
for(int i=1;i<=N;i++) sum[i]=sum[i-1]+mu[i];
}
ll calc(int n,int m){
if(n>m) swap(n,m);
ll ret=0;
for(int l=1,r;l<=n/k;l=r+1){
r=min(n/(n/l),m/(m/l));
ret+=(ll)(n/(l*k))*(m/(l*k))*(sum[r]-sum[l-1]);
}
return ret;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
PRE();
cin>>T;
while(T--){
int a,b,c,d;
cin>>a>>b>>c>>d>>k;
cout<<calc(a-1,c-1)-calc(b,c-1)-calc(d,a-1)+calc(b,d)<<"\n";
}
}
P2257 YY的GCD
上一题基础上我们口胡一下
\(=\large \sum\limits_{k\in Prime}^{min(n,m)}\sum\limits_{d=1}^{\min(n/k,m/k)}\mu(d)\lfloor\dfrac{n}{d}\rfloor \lfloor \dfrac{m}{d} \rfloor\)