「考試總結」20200724初音
A.字串識別
Description
Solution
這題問題出在了對於一個字尾自動機,這裡如果在 \(DAG\) 上面進行操作,複雜度是 \(O(n^2)\) 的
所以我們換個思路做,還是考慮那些 \(endpos\) 集合大小為 \(1\) 的字串
看看貢獻:
\[i\in [i-len_{fa_i}+1,i]\ \ \ \ ans_i=min(ans_i,len_{fa_i}+1) \]
\[i\in[i-len_i+1,i-len_{fa_i}] \ \ \ \ ans_i=min(ans_i,len_p-i+1) \]
對於第一種情況,線段樹統計答案
對於第二種情況,觀察到 \(ans_i\)
那麼先統一加上,然後最後面減掉,對位置減就好的
另外,區間取 \(min\) 的線段樹,需要好好記得怎麼寫……
Code
#include<bits/stdc++.h> using namespace std; namespace yspm{ inline int read() { int res=0,f=1; char k; while(!isdigit(k=getchar())) if(k=='-') f=-1; while(isdigit(k)) res=res*10+k-'0',k=getchar(); return res*f; } const int N=5e5+10,M=15e5+10; int ans[N],le; struct SGT{ int maxx[N<<2]; #define maxx(p) maxx[p] inline void build(int p,int l,int r,int val) { if(l==r) return maxx(p)=le+l*val,void(); int mid=(l+r)>>1; build(p<<1,l,mid,val); build(p<<1|1,mid+1,r,val); return maxx(p)=2e9+10,void(); } inline void update(int p,int st,int ed,int l,int r,int val) { if(l<=st&&ed<=r) return maxx(p)=min(maxx(p),val),void(); int mid=(st+ed)>>1; if(l<=mid) update(p<<1,st,mid,l,r,val); if(r>mid) update(p<<1|1,mid+1,ed,l,r,val); return ; } inline void work(int p,int st,int ed,int val) { if(st==ed) { ans[st]=min(ans[st],maxx(p)-val*st); return ; } int mid=(st+ed)>>1; maxx(p<<1)=min(maxx(p<<1),maxx(p)); maxx(p<<1|1)=min(maxx(p<<1|1),maxx(p)); work(p<<1,st,mid,val); work(p<<1|1,mid+1,ed,val); return ; } }T1,T2; struct edg{ int to,nxt; }e[M<<1]; int head[M],cnt; inline void add(int u,int v) { e[++cnt].to=v; e[cnt].nxt=head[u]; return head[u]=cnt,void(); } int son[M][26],fa[M],len[M],tot=1,r[M],las=1,sz[M]; inline void copy(int x,int y) { for(int i=0;i<26;++i) son[x][i]=son[y][i]; return ; } inline void extend(int x,int id) { int tmp=las,np=las=++tot; len[np]=len[tmp]+1; sz[np]=1; r[np]=id; while(tmp&&!son[tmp][x]) son[tmp][x]=np,tmp=fa[tmp]; if(!tmp) return fa[np]=1,void(); int q=son[tmp][x]; if(len[q]==len[tmp]+1) return fa[np]=q,void(); int clone=++tot; len[clone]=len[tmp]+1; fa[clone]=fa[q],fa[np]=fa[q]=clone; copy(clone,q); r[clone]=x; while(tmp&&son[tmp][x]==q) son[tmp][x]=clone,tmp=fa[tmp]; return ; } inline void dfs(int x) { for(int i=head[x];i;i=e[i].nxt) { int t=e[i].to; dfs(t); sz[x]+=sz[t]; } if(sz[x]==1) { T1.update(1,1,le,r[x]-len[fa[x]]+1,r[x],len[fa[x]]+1); T2.update(1,1,le,r[x]-len[x]+1,r[x]-len[fa[x]],len[x]+1); } return ; } char s[N]; signed main() { memset(ans,0x3f,sizeof(ans)); scanf("%s",s+1); le=strlen(s+1); T1.build(1,1,le,0); T2.build(1,1,le,1); for(int i=1;i<=le;++i) extend(s[i]-'a',i); for(int i=1;i<=tot;++i) add(fa[i],i); dfs(1); T1.work(1,1,le,0); T2.work(1,1,le,1); for(int i=1;i<=le;++i) printf("%d\n",ans[i]); return 0; } } signed main(){return yspm::main();}
B. CQOI2015 選數
Descripion
求
\[\sum_{a_1=L}^R \sum_{a_2=L}^R\dots\sum_{a_n=L}^R [gcd(a_1,a_2,a_3,\dots,a_n)=k] \ \ (mod\ 10^9+7) \]
所有參量滿足 \(\le 10^9\)
Solution
式子真難看,反手一推變成
\[\sum_{i=1}^{\lfloor \frac R k\rfloor} \mu(i) (\lfloor \frac {\lfloor \frac R k\rfloor} i\rfloor-\frac {\lfloor \frac L k\rfloor} i\rfloor)^n \]
(考試的時候推錯式子了……然後外加一些手殘就爆零了)
其實搞幾個變數代替一下就沒這麼麻煩了……
然後我們發現這種做法需要開不下的空間做 \(\mu\)
然後去學了一下杜教篩就做完了
或者容斥大佬會這種做法
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define inf (int)1e18+10
namespace yspm{
inline int read()
{
int res=0,f=1; char k;
while(!isdigit(k=getchar())) if(k=='-') f=-1;
while(isdigit(k)) res=res*10+k-'0',k=getchar();
return res*f;
}
const int mod=1e9+7;
inline int ksm(int x,int y)
{
int res=1;
for(;y;y>>=1,x=x*x%mod) if(y&1) res=res*x%mod;
return res;
}
inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
const int N=7e6+10;
bool fl[N];
int pri[N],cnt,mu[N],n,l,h,k,ans,low,up;
inline void prework()
{
mu[1]=1;
for(int i=2;i<N;++i)
{
if(!fl[i]) pri[++cnt]=i,mu[i]=mod-1;
for(int j=1;j<=cnt&&i*pri[j]<N;++j)
{
fl[i*pri[j]]=1;
if(i%pri[j]==0){mu[i*pri[j]]=0; break;}
else mu[i*pri[j]]=-mu[i],mu[i*pri[j]]=(mu[i*pri[j]]+mod)%mod;
}
}
for(int i=1;i<N;++i) mu[i]=add(mu[i],mu[i-1]);
return ;
}
map<int,int> mp;
inline void calc(int x,int &ans)
{
if(x<N) return ans=mu[x],void();
if(mp[x]) return ans=mp[x],void();
ans=1;
for(int l=2,r,s=0;l<=x;l=r+1)
{
r=x/(x/l); s=0;
calc(x/l,s);
(s+=mod)%mod;
ans-=(r-l+1)*s%mod;
ans=add(ans,mod);
} return mp[x]=ans,void();
}
inline int ask(int x)
{
int ans=0; calc(x,ans); return ans;
}
signed main()
{
n=read(); k=read(); l=read(); h=read();
low=(l-1)/k; up=h/k;
if(low>up) return puts("0"),0;
prework();
for(int i=1,j;i<=up;i=j+1)
{
j=min(low/i?low/(low/i):inf,up/(up/i));
ans=add(ans,(ask(j)-ask(i-1)+mod)%mod*ksm(up/i-low/i,n)%mod);
} cout<<ans<<endl;
return 0;
}
}
signed main(){return yspm::main();}
C.樹點塗色
最 \(sb\) 的一個題目了,不到二十天之前剛剛做完,然後今天就忘記了
不寫了,直接貼link
總結
感覺上午狀態很詭異,上手記錯了一個結論,線段樹寫了一個多小時,還妄想自己能 \(AK\) 結果呢?
就 \(20\)
好好的 \(lct\) 不會打,反演的式子還推錯
我服了我自己,慢慢考試慢慢進步吧