关于SMOJ校内模拟赛,表示本蒟蒻一篇博文都没写过(除了上次dp专题)。
今天做的题目一下子难度就upup,感觉整个人都是炸裂的。暴打选题人
那么接下来让我们看一看这些dalao眼中的水题。
回文数
【分析】
一看数据范围,显然是一道数学题。既然是数学题,那我们还是赶紧秒了吧。
首先很明显,我们可以看到,当i%2==0,并没有什么卵用,因为布尔表达式的值为0,也就是说,我们要求的回文串全都是长度为奇数的。这样一来,这个回文串就可以表示为ABA的形式。不难发现,我们令A为任意一个数字,B可以取0~9任意一个数字。有什么用呢?
例如我们取A的长度为3,那么长度为3的数字有多少个?答案是999-99=900个。那么很显然,我们长度为7的回文串个数(即ABA形式),一共有900*10=9000个,其中10代表B可以为0~9。
这样一来,当加上权值,我们可以得到这样一个东西:
令k=(n+1)/2;
S[i]=n*10^k-222…(k个2)+1
然后我们发现前面的
n*10^k
是一个快速幂
后面的
222…(k个2)
就是
111…(k个1)*2
这个是可以用一个等比数列弄出来的…
然后就可以做了。
(考试的时候用了矩阵乘法来做这个k个2…常数8,然而T了,优化失败又不想改lg,放弃)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL MAXN=4;
const LL mod=233333;
LL n,k,ans;
inline LL readin()
{
char ch=getchar();
LL u=0;
while(ch<'0' || ch>'9')
ch=getchar();
while(ch>='0' && ch<='9')
{
u=u*10+(ch-'0');
ch=getchar();
}
return u;
}
inline void init()
{
k=readin();
if(k%2==0)
--k;
n=k;
k=(k+1)/2;
}
inline LL mi(LL tp,LL tk)
{
--tk;
LL ret=tp;
for(;tk;tk>>=1,tp=(tp*tp)%mod)
{
if(tk&1)
ret=(ret*tp)%mod;
}
return ret%mod;
}
inline void solve()
{
// printf("%I64d\n",mi(10,k));
LL tmpmi=((mi(10,k)-1)%mod);
// printf("%I64d\n",tmpmi);
ans=(tmpmi*25926)%mod;
LL tenmi=mi(10,(n+1)>>1)%mod;
LL tfir=((1ll*n%mod)*tenmi)%mod;
ans=(ans*2)%mod;
LL las=(tfir-ans+1+mod)%mod;
printf("%lld\n",las);
}
int main()
{
freopen("2255.in","r",stdin);
freopen("2255.out","w",stdout);
int T=readin();
while(T--)
{
init();
solve();
}
return 0;
}
购物
【分析】
这题在考试的时候想着用线段树各种维护,然后果断炸了啊。
机房的scx在赛后5min码出了正解
其实这是一道比较水的dp (题面加难度系列) 设f[i]表示取到点i(商店i),的最大ans。
然后实际上,我们考虑每一个点,要取这个点,当且仅当有区间是可以覆盖到这个点的。那么我们就可以考虑,对于所有包含这个点的区间,我们取一个距离这个点最远的l(用lef[i]来记录),那么lef[i]到i这中间的所有点(用j来枚举)我们可以假设作为分割点,这样并不会影响到最后答案。
于是我们有:
f[i]=max(f[i],f[j-1]+sqr(sum[i]-sum[j-1]))。
其中sum表示到1~i商店的价值和。
注意有的点是不能被覆盖到的,这样f[i]为0,我们需要用一个ans来把前后的都加上。(详见代码)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int MAXN=5005;
int n,m;
int w[MAXN],lef[MAXN],sum[MAXN];
int ans,f[MAXN];
struct Tshop
{
int l,r;
};
Tshop a[MAXN*200];
inline int cmp(Tshop A,Tshop B)
{
if(A.l==B.l)
return A.r<B.r;
return A.l<B.l;
}
inline int sq(int x)
{
return x*x;
}
int main()
{
freopen("2256.in","r",stdin);
freopen("2256.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
{
scanf("%d",&w[i]);
sum[i]=sum[i-1]+w[i];
}
for(int i=1;i<=m;++i)
scanf("%d%d",&a[i].l,&a[i].r);
sort(a+1,a+m+1,cmp);
int tmp=1;
for(int i=1;i<=n;++i)
{
while(i>a[tmp].r && tmp<=m)
++tmp;
if(a[tmp].l<=i && i<=a[tmp].r)
lef[i]=a[tmp].l;
}
for(int i=1;i<=n;++i)
{
if(lef[i]>0)
for(int j=i;j>=lef[i];--j)
f[i]=max(f[i],f[j-1]+sq(sum[i]-sum[j-1]));
else
f[i]=f[i-1];
}
// if(lef[n]!=0)
// ans+=f[n];
printf("%d\n",f[n]);
return 0;
}
宗教
【分析】
正解后缀数组,利用height的特性,做RMQ,然后统计一下贡献。
说实话,关于字符串的题目本蒟蒻十分垃圾……
【代码】
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=(200000+5)*2;
int ans,n,s[MAXN],rmq[22][MAXN];
int sa[MAXN],c[MAXN],t[MAXN],t2[MAXN];
int rank[MAXN],height[MAXN],lg2[MAXN];
char a[MAXN],b[MAXN];
inline void get_sa(int m,int n)
{
int *x=t,*y=t2;
for(register int i=0;i<m;++i)
c[i]=0;
for(register int i=0;i<n;++i)
{
x[i]=s[i];
c[x[i]]++;
}
for(register int i=1;i<m;++i)
c[i]+=c[i-1];
for(register int i=n-1;i>=0;--i)
sa[--c[x[i]]]=i;
for(register int k=1;k<=n;k<<=1)
{
int p=0;
for(register int i=n-k;i<n;++i)
y[p++]=i;
for(register int i=0;i<n;++i)
if(sa[i]>=k)
y[p++]=sa[i]-k;
for(register int i=0;i<m;++i)
c[i]=0;
for(register int i=0;i<n;++i)
c[x[y[i]]]++;
for(register int i=0;i<m;++i)
c[i]+=c[i-1];
for(register int i=n-1;i>=0;--i)
sa[--c[x[y[i]]]]=y[i];
swap(x,y);
p=1;x[sa[0]]=0;
for(register int i=1;i<n;++i)
{
if(y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k])
x[sa[i]]=p-1;
else
x[sa[i]]=p++;
}
if(p>=n)
break;
m=p;
}
}
inline void get_height(int n)
{
int j,k=0;
for(register int i=0;i<=n;++i)
rank[sa[i]]=i;
for(register int i=0;i<n;++i)
{
if(k)
--k;
j=sa[rank[i]-1];
while(s[j+k]==s[i+k])
++k;
height[rank[i]]=k;
}
}
inline void get_rmq(int l,int r)
{
for (register int i=l;i<=r;i++)
rmq[0][i]=height[i+1];
for (register int j=1;j<=20;j++)
{
for (register int i=0;i<=r-(1<<j);i++)
{
rmq[j][i]=min(rmq[j-1][i],rmq[j-1][i+(1<<(j-1))]);
}
}
}
inline int RMQ(int aa,int bb)
{
if (aa>bb) swap(aa,bb);
int x=lg2[bb-aa];
return min(rmq[x][aa],rmq[x][bb-(1<<x)]);
}
inline void presolve()
{
lg2[0]=lg2[1]=0;
for (int i=2;i<=MAXN-10;i++)lg2[i]=lg2[i/2]+1;
}
int main()
{
freopen("2257.in","r",stdin);
freopen("2257.out","w",stdout);
presolve();
scanf("%s%s",a,b);
int K;
scanf("%d",&K);
int lena=strlen(a),lenb=strlen(b);
n=lena+lenb+1;
for(register int i=0;i<lena;++i)
s[i]=a[i];
s[lena]=1;
for(register int i=0;i<lenb;++i)
s[lena+i+1]=b[i];
s[n]=0;
get_sa('z'+1,n+1);
get_height(n);
get_rmq(0,n);
ans=0;
for (register int i=0;i<lena-lenb+1;i++)
{
int diff=0,pos=0;
while (diff<=K&&pos<lenb&&i+pos<lena)
{
int tmp=RMQ(rank[lena+1+pos],rank[pos+i]);
if (tmp==0)
diff++;
else if (pos+tmp<lenb)
diff++;
pos+=tmp+1;
}
if (diff<=K)
ans++;
}
printf("%d\n",ans);
return 0;
}
完结睡觉~