UPD 7.11 后两题的真正题解补完了
图游戏
n-1-m的奇偶性
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
int n,m;
int main() {
scanf("%d%d",&n,&m);
if ((n-1-m)&1) puts("Illyasviel");
else puts("Star-dust");
return 0;
}
双倍快乐
暴力枚举结尾,n^3
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=505;
int f[2][N][N],n,a[N];
int main() {
scanf("%d",&n);
fo(i,1,n) scanf("%d",&a[i]);
memset(f,128,sizeof(f));
f[0][0][0]=0;
fo(i,1,n) {
int t=i&1;
fo(j,0,i) fo(k,0,i) f[t][j][k]=f[t^1][j][k];
fo(j,0,i-1)
fo(k,0,i-1) {
if (a[i]>=a[j]) f[t][i][k]=max(f[t][i][k],f[t^1][j][k]+a[i]);
if (a[i]>=a[k]) f[t][j][i]=max(f[t][j][i],f[t^1][j][k]+a[i]);
}
}
int ans=0;
fo(i,1,n) fo(j,1,n) ans=max(ans,f[n&1][i][j]);
printf("%d\n",ans);
return 0;
}
一道树题
连通块数=点-边
考虑一个点会对哪些区间贡献
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define pb(a) push_back(a)
using namespace std;
typedef long long ll;
int read() {
char ch;
for(ch=getchar();ch<'0'||ch>'9';ch=getchar());
int x=ch-'0';
for(ch=getchar();ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x;
}
const int N=2e5+5;
int n;
vector<int> vec[N];
ll calc(ll x) {return x*(x+1)/2;}
int main() {
n=read();
fo(i,1,n-1) {
int x=read(),y=read();
vec[x].pb(i);vec[y].pb(i);
}
ll sum=(ll)n*(n-1)/2,ans=0;
fo(i,1,n) {
int la=0;ans+=sum;
for(int j=0;j<vec[i].size();j++) {
ans-=calc(vec[i][j]-la-1);
la=vec[i][j];
}
ans-=calc(n-1-la);
}
fo(i,1,n-1) ans-=(ll)i*(n-i);
printf("%lld\n",ans);
return 0;
}
另一道树题
考虑一开始每个点都有一个棋子,每一轮把每个棋子移到其父亲处
设C[i][j]表示i轮后点j上的棋子数,答案为
∑
∏
j
=
1
n
(
C
[
i
]
[
j
]
+
1
)
−
N
−
1
\sum\prod_{j=1}^{n}(C[i][j]+1)-N-1
∑∏j=1n(C[i][j]+1)−N−1
考虑用长链剖分维护C[i],注意到C[i]的值只会产生O(n)次修改,每次修改时处理贡献即可
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define rep(i,a) for(int i=lst[a];i;i=nxt[i])
using namespace std;
typedef long long ll;
int read() {
char ch;
for(ch=getchar();ch<'0'||ch>'9';ch=getchar());
int x=ch-'0';
for(ch=getchar();ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x;
}
const int N=4e5+5,Mo=998244353;
int pwr(int x,int y) {
int z=1;
for(;y;y>>=1,x=(ll)x*x%Mo)
if (y&1) z=(ll)z*x%Mo;
return z;
}
int t[N<<1],nxt[N<<1],lst[N],l;
void add(int x,int y) {t[++l]=y;nxt[l]=lst[x];lst[x]=l;}
int n,dep[N],mx[N],f[N],an[N],son[N],dfn[N],id[N],la[N],cnt[N],tot;
void dfs(int x) {
mx[x]=x;
rep(i,x) {
dep[t[i]]=dep[x]+1;dfs(t[i]);
if (dep[mx[t[i]]]>dep[mx[x]]) mx[x]=mx[t[i]],son[x]=t[i];
}
}
void make(int x) {
dfn[x]=++tot;
if (!son[x]) return;
make(son[x]);
rep(i,x) if (t[i]!=son[x]) make(t[i]);
}
void inc(int &x,int y) {x=x+y>=Mo?x+y-Mo:x+y;}
void mdf(int l,int r,int c) {an[l]=(ll)an[l]*c%Mo;an[r+1]=(ll)an[r+1]*pwr(c,Mo-2)%Mo;}
void dp(int x) {
rep(i,x) dp(t[i]);
f[dfn[x]]=1;la[dfn[x]]=0;int m=0;
rep(i,x) if (t[i]!=son[x]) m=max(m,dep[mx[t[i]]]-dep[t[i]]+1);
fo(j,1,m) {
mdf(la[dfn[x]+j],j-1,f[dfn[x]+j]+1);
la[dfn[x]+j]=j;
}
rep(i,x)
if (t[i]!=son[x])
fo(j,0,dep[mx[t[i]]]-dep[t[i]]) {
inc(f[dfn[x]+j+1],f[dfn[t[i]]+j]);
mdf(la[dfn[t[i]]+j],j,f[dfn[t[i]]+j]+1);
}
}
int main() {
n=read();
fo(i,2,n) {
int x=read();
add(x,i);
}
fo(i,0,n) an[i]=1;
dfs(1);make(1);dp(1);
fo(i,1,n) cnt[dep[i]]++;
fo(i,0,dep[mx[1]]) mdf(la[1+i],i,f[1+i]+1);
fo(i,1,dep[mx[1]]) an[i]=(ll)an[i]*an[i-1]%Mo;
int sum=0;
fo(i,0,dep[mx[1]]) {
sum+=cnt[i];
an[i]=(ll)an[i]*pwr(cnt[i]+1,Mo-2)%Mo;
an[i]=(ll)an[i]*(sum+1)%Mo;
}
int ans=0;
fo(i,0,dep[mx[1]]) {
(ans+=an[i])%=Mo;
(ans-=n+1)%=Mo;
}
printf("%d\n",(ans+Mo)%Mo);
return 0;
}
字符串
若后缀i和j的lcp为l
贡献为
∑
k
=
0
l
−
1
k
∗
(
i
+
j
−
2
∗
k
+
1
)
+
l
∗
(
i
−
l
+
1
)
∗
(
j
−
l
+
1
)
\sum_{k=0}^{l-1}k*(i+j-2*k+1)+l*(i-l+1)*(j-l+1)
∑k=0l−1k∗(i+j−2∗k+1)+l∗(i−l+1)∗(j−l+1)
拆开来维护一坨东西,用链剖维护前缀的差分即可做到O(n log^2 n)
TLE到飞起
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int N=4e5+5,Mo=998244353;
void write(ll x) {
if (!x) {putchar('0');return;}
char ch[20];int tot=0;
for(;x;x/=10) ch[++tot]=x%10+'0';
fd(i,tot,1) putchar(ch[i]);
}
int n,lst,pos[N],fa[N],tot;
char st[N];
struct SAM{int son[26],len,pr;}sam[N];
int extend(int x,int p) {
int np=++tot;sam[np].len=sam[p].len+1;
while (p&&!sam[p].son[x]) sam[p].son[x]=np,p=sam[p].pr;
if (!p) sam[np].pr=1;else {
int q=sam[p].son[x];
if (sam[q].len==sam[p].len+1) sam[np].pr=q;
else {
int nq=++tot;
sam[nq]=sam[q];
sam[nq].len=sam[p].len+1;
sam[q].pr=sam[np].pr=nq;
while (p&&sam[p].son[x]==q) sam[p].son[x]=nq,p=sam[p].pr;
}
}
return np;
}
ll an[N];
vector<int> son[N];
int s[N],sz[N],top[N],dfn[N],id[N],tmp;
void dfs(int x) {
sz[x]=1;int k=0;
for(int z:son[x]) {
dfs(z);
sz[x]+=sz[z];
if (sz[z]>k) k=sz[z],s[x]=z;
}
}
void make(int x,int y) {
top[x]=y;dfn[x]=++tmp;id[tmp]=x;
if (!s[x]) return;
make(s[x],y);
for(int z:son[x]) {
if (z==s[x]) continue;
make(z,z);
}
}
// 0 (t+1)*∑l
// 1 ∑l
// 2 ∑l*l
// 3 (t+1)*l
// 4 l*l
// 5 (t+1)*l*l
// 6 l*l*l
int s1[N],s2[N],p1[N],p2[N],p3[N];
ll tr[N<<2][7],tg_t[N<<2],tg_c[N<<2],a[7];
void upd(int v) {fo(i,0,6) tr[v][i]=(tr[v<<1][i]+tr[v<<1|1][i])%Mo;}
void apply(int v,int l,int r,ll t,ll c) {
(tr[v][0]+=t*(s1[sam[id[r]].len]-s1[sam[fa[id[l]]].len]))%=Mo;
(tr[v][1]+=c*(s1[sam[id[r]].len]-s1[sam[fa[id[l]]].len]))%=Mo;
(tr[v][2]+=c*(s2[sam[id[r]].len]-s2[sam[fa[id[l]]].len]))%=Mo;
(tr[v][3]+=t*(p1[sam[id[r]].len]-p1[sam[fa[id[l]]].len]))%=Mo;
(tr[v][4]+=c*(p2[sam[id[r]].len]-p2[sam[fa[id[l]]].len]))%=Mo;
(tr[v][5]+=t*(p2[sam[id[r]].len]-p2[sam[fa[id[l]]].len]))%=Mo;
(tr[v][6]+=c*(p3[sam[id[r]].len]-p3[sam[fa[id[l]]].len]))%=Mo;
(tg_t[v]+=t)%=Mo;tg_c[v]+=c;
}
void down(int v,int l,int r) {
if (tg_t[v]||tg_c[v]) {
int mid=l+r>>1;
apply(v<<1,l,mid,tg_t[v],tg_c[v]);
apply(v<<1|1,mid+1,r,tg_t[v],tg_c[v]);
tg_t[v]=0;tg_c[v]=0;
}
}
void modify(int v,int l,int r,int x,int y,int z) {
if (x<=l&&r<=y) {apply(v,l,r,z,1);return;}
int mid=l+r>>1;down(v,l,r);
if (x<=mid) modify(v<<1,l,mid,x,y,z);
if (y>mid) modify(v<<1|1,mid+1,r,x,y,z);
upd(v);
}
void query(int v,int l,int r,int x,int y) {
if (x<=l&&r<=y) {
fo(i,0,6) a[i]+=tr[v][i];
return;
}
int mid=l+r>>1;down(v,l,r);
if (x<=mid) query(v<<1,l,mid,x,y);
if (y>mid) query(v<<1|1,mid+1,r,x,y);
upd(v);
}
void Mdf(int x,int l) {for(;x;x=fa[top[x]]) modify(1,1,tot,dfn[top[x]],dfn[x],l);}
void Que(int x) {
fo(i,0,6) a[i]=0;
for(;x;x=fa[top[x]]) query(1,1,tot,dfn[top[x]],dfn[x]);
}
int calc(int l) {
int ret=l;
(ret+=(ll)(2*l+1)*l*(l-1)/2%Mo)%=Mo;
(ret-=(ll)(l-1)*l*(2*l-1)/3%Mo)%=Mo;
/*ret+=(s+1)*(t+1)*l;
ret-=(s+1)*l*l;
ret-=(t+1)*l*l;
ret+=l*l*l;*/
return ret;
}
int main() {
scanf("%s",st+1);n=strlen(st+1);
reverse(st+1,st+n+1);
lst=tot=1;
fo(i,1,n) pos[i]=lst=extend(st[i]-'a',lst);
fo(i,2,tot) fa[i]=sam[i].pr,son[fa[i]].push_back(i);
fo(i,1,n) s1[i]=s1[i-1]+i-1;
fo(i,1,n) s2[i]=(s2[i-1]+(ll)(i-1)*(i-1)%Mo)%Mo;
fo(i,1,n) p1[i]=i,p2[i]=(ll)i*i%Mo,p3[i]=(ll)i*i*i%Mo;
dfs(1);make(1,1);
fo(i,1,n) {
Que(pos[i]);
fo(i,0,6) a[i]%=Mo;
an[i]+=a[0];
an[i]+=(ll)a[1]*i;
an[i]-=a[2]*2;
an[i]+=(ll)a[3]*(i+1);
an[i]-=(ll)a[4]*(i+1);
an[i]-=a[5];an[i]+=a[6];
an[i]=(an[i]*2%Mo+calc(i))%Mo;
Mdf(pos[i],i+1);
}
fo(i,1,n) an[i]+=an[i-1];
fd(i,n,1) printf("%lld ",(an[i]+Mo)%Mo);
return 0;
}