test20231104
T1
简单题,可以做到 \(n^2\) 但是没必要, \(n^3\) 已经很快了。
int n,m;
char a[550][550];
int h[550][550],ans;
signed main(){
n=read();m=read();
up(i,1,n){
scanf("%s",a[i]+1);
}
up(i,1,n){
up(j,1,m){
if(a[i][j]=='.')h[i][j]=h[i-1][j]+1;
else h[i][j]=0;
}
up(j,1,m){
if(h[i][j]==0)continue;
int L=j,R=j,x=h[i][j];
while(R<m&&h[i][R+1]>=x)R++;
while(L>1&&h[i][L-1]>=x)L--;
ans=max(ans,2*(R-L+1+x)-1);
}
}
cout<<ans;
return 0;
}
T2
tmd,看到只有五个数,想着直接推数学公式,然推退了两个小时,然后打了个 \(O(n)\) 的 dp,然后看出来了要用矩阵快速幂,但是写挂了,而且也没有时间调代码了。
先简单写一个暴力 dp。
cnt[0][1]=1;
cnt[0][0]=1;
g[0][0]=e;
g[0][1]=d;
up(i,1,30){
int pre1=i-a;
if(pre1>=0){
cnt[i][1]=(cnt[i][1]+cnt[pre1][1])%mod;
g[i][1]=(g[i][1]+g[pre1][1]+cnt[pre1][1]*d)%mod;
}
int pre2=i-b;
if(pre2>=0){
cnt[i][1]=(cnt[i][1]+cnt[pre2][0])%mod;
cnt[i][0]=(cnt[i][0]+cnt[pre2][1])%mod;
g[i][1]=(g[i][1]+g[pre2][0]+cnt[pre2][0]*d)%mod;
g[i][0]=(g[i][0]+g[pre2][1]+cnt[pre2][1]*e)%mod;
}
int pre3=i-c;
if(pre3>=0){
cnt[i][0]=(cnt[i][0]+cnt[pre3][0])%mod;
g[i][0]=(g[i][0]+g[pre3][0]+cnt[pre3][0]*e)%mod;
}
}
我们发现 \(a,b,c\le30\),所以我们可以用一个矩阵把 \([i-30,i]\) 的情况记录下来,然后构造转移矩阵。
难吗?真的不难,只是繁琐而已。
int n,a,b,c,d,e;
int cnt[55][2],g[55][2];
struct mat{
int a[205][205];
mat(){
memset(a,0,sizeof a);
}
inline mat operator*(const mat&rhs)const{
mat res;
up(i,1,130){
up(j,1,130){
up(k,1,130){
res.a[i][j]=(res.a[i][j]+a[i][k]*rhs.a[k][j])%mod;
}
}
}
return res;
}
inline void init(){
up(i,1,190)a[i][i]=1;
}
}A,B;
inline mat ksm(mat a,int b){
mat res;
res.init();
while(b){
if(b&1)res=res*a;
a=a*a;
b>>=1;
}
return res;
}
signed main(){
n=read();
a=read();b=read();c=read();
d=read();e=read();
cnt[0][1]=1;
cnt[0][0]=1;
g[0][0]=e;
g[0][1]=d;
up(i,1,30){
int pre1=i-a;
if(pre1>=0){
cnt[i][1]=(cnt[i][1]+cnt[pre1][1])%mod;
g[i][1]=(g[i][1]+g[pre1][1]+cnt[pre1][1]*d)%mod;
}
int pre2=i-b;
if(pre2>=0){
cnt[i][1]=(cnt[i][1]+cnt[pre2][0])%mod;
cnt[i][0]=(cnt[i][0]+cnt[pre2][1])%mod;
g[i][1]=(g[i][1]+g[pre2][0]+cnt[pre2][0]*d)%mod;
g[i][0]=(g[i][0]+g[pre2][1]+cnt[pre2][1]*e)%mod;
}
int pre3=i-c;
if(pre3>=0){
cnt[i][0]=(cnt[i][0]+cnt[pre3][0])%mod;
g[i][0]=(g[i][0]+g[pre3][0]+cnt[pre3][0]*e)%mod;
}
}
if(n<=30){
cout<<(g[n][0]+g[n][1])%mod<<endl;
return 0;
}
n-=30;
up(i,1,31)A.a[1][i]=cnt[i-1][0];
up(i,32,62)A.a[1][i]=cnt[i-32][1];
up(i,63,93)A.a[1][i]=g[i-63][0];
up(i,94,124)A.a[1][i]=g[i-94][1];
up(i,0,3){
up(j,0,29){
B.a[i*31+1+j+1][i*31+1+j]=1;
}
}
B.a[31-c+1][31]=1;
B.a[31+31-b+1][31]=1;
B.a[31+31-a+1][62]=1;
B.a[31-b+1][62]=1;
B.a[31-c+1][93]=e;
B.a[31+31-b+1][93]=e;
B.a[31*2+31-c+1][93]=1;
B.a[31*3+31-b+1][93]=1;
B.a[31+31-a+1][124]=d;
B.a[31-b+1][124]=d;
B.a[31*3+31-a+1][124]=1;
B.a[31*2+31-b+1][124]=1;
A=A*ksm(B,n);
cout<<(A.a[1][93]+A.a[1][124])%mod;
return 0;
}
T3
简单题,字典树上 dfs 就行了。
int n;
int tr[M][26],dep[M],tim[M];
int cnt;
inline void insert(string s){
int p=0;
up(i,0,s.size()-1){
int ch=s[i]-'a';
if(!tr[p][ch])tr[p][ch]=++cnt,dep[cnt]=dep[p]+1;
p=tr[p][ch];
tim[p]++;
}
}
int sz[M],del[M];
inline void insert2(string s){
int p=0;
up(i,0,s.size()-1){
int ch=s[i]-'a';
if(!tr[p][ch])break;
p=tr[p][ch];
}
sz[p]++;
}
int ans;
inline void dfs(int u){
up(i,0,25){
if(tr[u][i]==0)continue;
dfs(tr[u][i]);
sz[u]+=sz[tr[u][i]];
del[u]+=del[tr[u][i]];
}
tim[u]-=del[u];
if(sz[u]>=tim[u]){
ans+=tim[u]*dep[u];
sz[u]-=tim[u];
del[u]+=tim[u];
}
else {
ans+=sz[u]*dep[u];
del[u]+=sz[u];
sz[u]=0;
}
}
signed main(){
ios_base::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n;
string s;
up(i,1,n){
cin>>s;
insert(s);
}
up(i,1,n){
cin>>s;
insert2(s);
}
dfs(0);
cout<<ans<<endl;;
return 0;
}
T4
以 T4 的水准来说应该算是一道简单题,思维并不复杂。
重点:抽屉原理,一个区间不会长度超过 \(14\)。
每次操作等于是把幂次乘上 \(3\)。
由于 \(a_i\) 到最后一定是为 \(a_i^{3^k}\),所以我们可以直接暴力倍增,然后分解 \(k\) 就行了。
int n,m,v,phi;
int a[N];
int dp[N][22];
inline void init(){
up(i,0,v-1)dp[i][0]=i*i*i%v;
up(j,1,20){
up(i,0,v-1){
dp[i][j]=dp[dp[i][j-1]][j-1];
}
}
}
struct SegmentTree{
struct node{
int l,r,tag;
}tr[N<<2];
inline void build(int k,int l,int r){
tr[k].l=l;tr[k].r=r;tr[k].tag=0;
if(l==r)return;
int mid=(l+r)>>1;
build(lc,l,mid);
build(rc,mid+1,r);
}
inline void push_down(int k){
if(tr[k].tag!=0){
tr[lc].tag=tr[k].tag+tr[lc].tag;
tr[rc].tag=tr[rc].tag+tr[k].tag;
tr[k].tag=0;
}
}
inline void plus(int k,int l,int r){
if(tr[k].l>=l&&tr[k].r<=r){
tr[k].tag++;
return;
}
int mid=(tr[k].l+tr[k].r)>>1;
push_down(k);
if(mid>=l)plus(lc,l,r);
if(mid<r)plus(rc,l,r);
}
inline void clac(int&ans,int&r){
int j=20;
while(j>=0){
if(r>=(1<<j)){
ans=dp[ans][j];
r-=(1<<j);
if(r==0)break;
}
j--;
}
return;
}
inline void ask(int k,int l,int r){
if(tr[k].l==tr[k].r){
clac(a[tr[k].l],tr[k].tag);
return;
}
int mid=(tr[k].l+tr[k].r)>>1;
push_down(k);
if(mid>=l)ask(lc,l,r);
if(mid<r)ask(rc,l,r);
}
}T;
bool flag;
bool vis[N];
int sta[N],cnt;
inline void dfs1(int u,int lim,int sum,bool lead){
if(flag)return;
if(u==lim+1){
if(lead==1){
if(sum==0)flag=1;
else if(sum>0&&!vis[sum]){
vis[sum]=1;
sta[++cnt]=sum;
}
}
return;
}
dfs1(u+1,lim,sum+a[u]+1,1);
dfs1(u+1,lim,sum-a[u]-1,1);
dfs1(u+1,lim,sum,lead);
}
inline void dfs2(int u,int lim,int sum,bool lead){
if(flag)return;
if(u==lim+1){
if(lead==1){
if(sum==0)flag=1;
else if(sum>0&&vis[sum])flag=1;
}
return;
}
dfs2(u+1,lim,sum,lead);
dfs2(u+1,lim,sum+a[u]+1,1);
dfs2(u+1,lim,sum-a[u]-1,1);
}
signed main(){
n=read();m=read();v=read();
init();
up(i,1,n)a[i]=read();
T.build(1,1,n);
int l,r,op;
while(m--){
op=read();
if(op==1){
l=read();r=read();
if(r-l+1>=14)puts("Yes");
else{
T.ask(1,l,r);
flag=0;cnt=0;
int mid=(l+r)>>1;
dfs1(l,mid,0,0);
dfs2(mid+1,r,0,0);
if(flag)puts("Yes");
else puts("No");
up(i,1,cnt)vis[sta[i]]=0;
}
}
else{
l=read(),r=read();
T.plus(1,l,r);
}
}
return 0;
}