前言
md又是rk4_(:з」∠)_
可惜了要是ilnil过了E我们机房就可以加一个冰箱了
题目链接
eon
模拟
Code
#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 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=1e6+5;
char st[N];
int main() {
scanf("%s",st+1);int n=strlen(st+1);
int mn=10;
fo(i,1,n) mn=min(mn,st[i]-'0');
mn-=(st[n]-'0');
printf("%d\n",(mn+10)%10);
return 0;
}
usiness
Dp
Code
#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 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=105,K=2e3+5,inf=0x7fffffff;
int f[K],g[K],n,m,k,mx,val[K],a[N],b[N];
int main() {
n=read();m=read();k=read();
fo(i,0,k) val[i]=read(),mx=max(mx,val[i]);
fo(i,1,m) a[i]=read(),b[i]=read();
fo(j,0,k+mx) f[j]=-inf;
f[0]=0;
fo(i,1,n) {
fo(w,1,m) fd(j,k+mx,a[w]) f[j-a[w]]=max(f[j-a[w]],f[j]+b[w]);
fo(j,0,k+mx) g[j]=-inf;
fo(j,0,k+mx) g[j+val[j]]=max(g[j+val[j]],f[j]);
fo(j,0,k+mx) f[j]=g[j];
}
int ans=-inf;
fo(i,0,k+mx) ans=max(ans,f[i]+i);
printf("%d\n",ans);
return 0;
}
elebration
一开始觉得好麻烦啊就跳了
后来看发现由于性质优美不需要讨论
考虑a+b+c=n,a,b,c能够成三角形的充要条件为
a
,
b
,
c
<
⌊
n
+
1
2
⌋
a,b,c\lt{\lfloor{{n+1}\over 2}\rfloor}
a,b,c<⌊2n+1⌋
预处理出对于每个i,往左右最长能延伸多长
考虑枚举第一段的开头,设为i,那么第二段开头j会满足
i
<
j
≤
R
[
i
]
+
1
i\lt j\le R[i]+1
i<j≤R[i]+1
第三段开头k会满足
j
<
k
≤
R
[
j
]
+
1
j\lt k\le R[j]+1
j<k≤R[j]+1,且
k
≥
L
[
i
+
n
−
1
]
−
1
k\ge L[i+n-1]-1
k≥L[i+n−1]−1
枚举了i和j,那么合法的k的数量是
L
[
i
+
n
−
1
]
−
R
[
j
]
+
2
L[i+n-1]-R[j]+2
L[i+n−1]−R[j]+2
由于R是单调递增的,可以用双指针维护合法的j的取值区间
剩下的用一个R的前缀和计数即可
复杂度
O
(
n
)
O(n)
O(n)
Code
#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;
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=4e6+5;
int n,m,a[N],lst[N],L[N],R[N];
ll s[N];
int main() {
n=read();m=((n+1)>>1)-1;
fo(i,1,n) a[i]=read();
fo(i,n+1,n<<1) a[i]=a[i-n];
fo(i,1,n) lst[i]=0;
fo(i,1,n<<1) {
L[i]=max(L[i-1],lst[a[i]]+1);
lst[a[i]]=i;
}
fo(i,1,n) lst[i]=n<<1|1;R[n<<1|1]=n<<1|1;
fd(i,n<<1,1) {
R[i]=min(R[i+1],lst[a[i]]-1);
lst[a[i]]=i;
}
fo(i,1,n<<1) {
if (i-L[i]+1>m) L[i]=i-m+1;
if (R[i]-i+1>m) R[i]=i+m-1;
}
fo(i,1,n<<1) s[i]=s[i-1]+R[i];
ll ans=0;int j=0;
fo(i,1,n) {
j=max(j,i);
while (j<=(n<<1)&&j<=R[i]&&R[j+1]<L[i+n-1]-1) j++;
if (j<=(n<<1)&&(j<=R[i])) {
ans+=s[R[i]+1]-s[j];
ans-=(ll)(L[i+n-1]-2)*(R[i]-j+1);
}
}
printf("%lld\n",ans/3);
return 0;
}
isaster
构出kruskal重构树,问题变成单点修改子树查询
线段树维护区间乘积即可
Code
#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=2e5+5,Mo=998244353;
int t[N],nxt[N],lst[N],l;
void add(int x,int y) {t[++l]=y;nxt[l]=lst[x];lst[x]=l;}
int n,m,q,fa[N][18],f[N],val[N],a[N];
struct Edge{int x,y,z;}e[N];
bool cmp(Edge a,Edge b) {return a.z<b.z;}
int get(int x) {return f[x]?f[x]=get(f[x]):x;}
int jump(int x,int y) {
fd(i,17,0) if (fa[x][i]&&val[fa[x][i]]<=y) x=fa[x][i];
return x;
}
int tot,dfn[N],sz[N];
void dfs(int x) {
dfn[x]=++tot;sz[x]=1;
rep(i,x) dfs(t[i]),sz[x]+=sz[t[i]];
}
int tr[N<<2];
void modify(int v,int l,int r,int x,int y) {
if (l==r) {tr[v]=y;return;}
int mid=l+r>>1;
if (x<=mid) modify(v<<1,l,mid,x,y);
else modify(v<<1|1,mid+1,r,x,y);
tr[v]=(ll)tr[v<<1]*tr[v<<1|1]%Mo;
}
int query(int v,int l,int r,int x,int y) {
if (x<=l&&r<=y) return tr[v];
int mid=l+r>>1,tmp=1;
if (x<=mid) tmp=(ll)tmp*query(v<<1,l,mid,x,y)%Mo;
if (y>mid) tmp=(ll)tmp*query(v<<1|1,mid+1,r,x,y)%Mo;
return tmp;
}
int main() {
n=read();m=read();q=read();
fo(i,1,n) a[i]=read()%Mo;
fo(i,1,m) e[i].x=read(),e[i].y=read(),e[i].z=max(e[i].x,e[i].y);
sort(e+1,e+m+1,cmp);
int tmp=n;
fo(i,1,m) {
int x=get(e[i].x),y=get(e[i].y);
if (x==y) continue;
val[++tmp]=e[i].z;
fa[x][0]=fa[y][0]=tmp;
add(tmp,x);add(tmp,y);
f[x]=f[y]=tmp;
}
fo(j,1,17) fo(i,1,tmp) fa[i][j]=fa[fa[i][j-1]][j-1];
dfs(tmp);
fo(i,1,n) modify(1,1,tmp,dfn[i],a[i]);
fo(i,n+1,tmp) modify(1,1,tmp,dfn[i],1);
for(;q;q--) {
int opt=read(),x=read(),y=read();
if (opt==1) {
if (x>y) {puts("0");continue;}
int z=jump(x,y);
printf("%d\n",query(1,1,tmp,dfn[z],dfn[z]+sz[z]-1));
}
if (opt==2) modify(1,1,tmp,dfn[x],y%Mo);
}
return 0;
}
ffort
比赛时想复杂了没写出来(搞了个要写多项式取模的
考虑总和为k,分给左边的方案数为a,分给右边的方案数为b,那么答案就是∑a*b
注意b相当于在k中插n-1个板的方案数
于是我们可以维护多项式
F
i
(
x
)
F_i(x)
Fi(x),x^k的系数表示插k个板的方案数,即
∑
j
=
1
b
i
(
j
k
)
=
(
j
+
1
k
+
1
)
−
[
k
=
=
0
]
\sum_{j=1}^{b_i}\binom{j}{k}=\binom{j+1}{k+1}-[k==0]
∑j=1bi(kj)=(k+1j+1)−[k==0]
那么求出
∏
F
i
a
i
(
x
)
\prod F_i^{a_i}(x)
∏Fiai(x)即可
注意我们计算的时候是默认可以在最后一个插板的,实际上是不行的,所以最后需要一个容斥才能求出最终答案
直接快速幂是
O
(
n
m
log
n
log
a
)
O(nm \log n \log a)
O(nmlognloga),用ln/exp可以做到
O
(
n
m
log
n
)
O(nm \log n)
O(nmlogn)
Code
#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;
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=(1<<18)+5,Mo=998244353;
ll pwr(ll x,ll y) {
ll z=1;
for(;y;y>>=1,x=x*x%Mo)
if (y&1) z=z*x%Mo;
return z;
}
int n,m,a[N],b[N],rev[N],lg,len;
ll W[2][N],inv[N],f[N],g[N],an[N];
void init(int N) {
for(int i=1;i<N;i<<=1) {
ll wn=pwr(3,(Mo-1)/(i<<1));
for(int j=0;j<i;j++) W[1][i+j]=(j?W[1][i+j-1]*wn%Mo:1);
wn=pwr(3,Mo-1-(Mo-1)/(i<<1));
for(int j=0;j<i;j++) W[0][i+j]=(j?W[0][i+j-1]*wn%Mo:1);
}
inv[0]=inv[1]=1;fo(i,2,N) inv[i]=-Mo/i*inv[Mo%i]%Mo;
}
void DFT(ll *a,int len,int flag) {
for(int i=0;i<len;i++) if (i<rev[i]) swap(a[i],a[rev[i]]);
if (flag==-1) flag=0;
for(int i=1;i<len;i<<=1)
for(int j=0;j<len;j+=i<<1)
for(int k=0;k<i;k++) {
ll u=a[j+k],v=a[j+k+i]*W[flag][i+k]%Mo;
a[j+k]=(u+v)%Mo;a[j+k+i]=(u-v)%Mo;
}
if (flag==0) for(int i=0;i<len;i++) a[i]=a[i]*inv[len]%Mo;
}
void mult(ll *a,ll *b,ll *c) {
static ll ta[N],tb[N];
fo(i,0,len-1) ta[i]=tb[i]=0;
fo(i,0,n-1) ta[i]=a[i],tb[i]=b[i];
DFT(ta,len,1);DFT(tb,len,1);
fo(i,0,len-1) ta[i]=ta[i]*tb[i]%Mo;
DFT(ta,len,-1);
fo(i,0,n-1) c[i]=ta[i];
}
int main() {
init(1<<18);
n=read();m=read();
for(len=1;len<=(n<<1);len<<=1) lg++;
fo(i,0,len-1) rev[i]=rev[i>>1]>>1|((i&1)<<lg-1);
an[0]=1;
fo(i,1,m) {
a[i]=read();b[i]=read();
fo(j,0,n-1) f[j]=(j?f[j-1]*(b[i]+1-j)%Mo*inv[j+1]%Mo:b[i]+1);f[0]--;
for(;a[i];a[i]>>=1,mult(f,f,f)) if (a[i]&1) mult(an,f,an);
}
ll ans=0;
fo(i,0,n-1) (ans+=((n-1-i)&1?-1:1)*an[i])%=Mo;
printf("%lld\n",(ans+Mo)%Mo);
return 0;
}
arewell
先考虑3^n如何Dp
设F[s]表示s内部已经是一个DAG的方案数,考虑枚举入度为0的点,我们有
F
[
s
]
=
∑
t
⊂
s
F
[
t
]
∗
2
c
(
s
−
t
,
t
)
F[s]=\sum_{t\subset s}F[t]*2^{c(s-t,t)}
F[s]=t⊂s∑F[t]∗2c(s−t,t)
c(s,t)表示集合s和集合t之间的边数
但是这个是不对的,因为我们只能保证至少那些点是入度为0的而不是恰好所以应该要套一个容斥
F
[
s
]
=
∑
t
⊂
s
F
[
t
]
∗
2
c
(
s
−
t
,
t
)
∗
(
−
1
)
p
o
p
c
o
u
n
t
(
s
−
t
)
+
1
F[s]=\sum_{t\subset s}F[t]*2^{c(s-t,t)}*(-1)^{popcount(s-t)+1}
F[s]=t⊂s∑F[t]∗2c(s−t,t)∗(−1)popcount(s−t)+1
这样还不够,我们需要继续优化
设p[s]表示集合s内部的边数,我们有c(s,t)=p(s|t)-p(s)-p(t)
于是就变成了
F
[
s
]
2
p
(
s
)
=
∑
t
⊂
s
F
[
t
]
2
p
(
t
)
∗
1
2
p
(
s
−
t
)
∗
(
−
1
)
p
o
p
c
o
u
n
t
(
s
−
t
)
+
1
{F[s]\over 2^{p(s)}}=\sum_{t\subset s}{F[t]\over 2^{p(t)}}*{1\over 2^{p(s-t)}} *(-1)^{popcount(s-t)+1}
2p(s)F[s]=t⊂s∑2p(t)F[t]∗2p(s−t)1∗(−1)popcount(s−t)+1
然后就是子集卷积的形式了,直接上板子即可
复杂度
O
(
2
n
n
2
)
O(2^nn^2)
O(2nn2)
抢了个一血很舒服
Code
#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=25,S=(1<<20)+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 f[N][S],g[N][S],cnt[S],p[S],pw[N*N],inv[N*N],n,m,u[N*N],v[N*N];
void FWT(int *a){for(int i=2,j,m,k;m=i>>1,i<=(1<<n);i<<=1)for(int j=0;j<(1<<n);j+=i)for(k=0;k<m;++k)(a[j+k+m]+=a[j+k])%=Mo;}
int main() {
scanf("%d%d",&n,&m);
fo(i,1,m) scanf("%d%d",&u[i],&v[i]);
pw[0]=1;fo(i,1,m) pw[i]=(pw[i-1]<<1)%Mo;
fo(i,0,m) inv[i]=pwr(pw[i],Mo-2);
fo(s,1,(1<<n)-1) cnt[s]=cnt[s>>1]+(s&1);
fo(s,0,(1<<n)-1) fo(i,1,m) if ((s>>(u[i]-1)&1)&&(s>>(v[i]-1)&1)) p[s]++;
fo(s,1,(1<<n)-1) g[cnt[s]][s]=(cnt[s]&1)?inv[p[s]]:(Mo-inv[p[s]])%Mo;
fo(i,1,n) FWT(g[i]);
fo(s,0,(1<<n)-1) f[0][s]=1;
fo(i,1,n) fo(j,0,i-1) fo(s,0,(1<<n)-1) if (f[j][s]&&g[i-j][s]) f[i][s]=(f[i][s]+(ll)f[j][s]*g[i-j][s])%Mo;
ll ans=0;
fo(s,0,(1<<n)-1) ans+=cnt[(1<<n)-1-s]&1?-f[n][s]:f[n][s];
ans=ans%Mo*pwr(pwr(3,Mo-2),m)%Mo*pw[m]%Mo;
printf("%d\n",(ans+Mo)%Mo);
return 0;
}