NOI模拟20220605
今天的题确实是难,我仅有50pts,被吊打了eeeeeeeeee
T1 求和
题面越简单,题目越难,这似乎是公认的道理了
但是这个可以找规律哦,直接对着杨辉三角搞就好了,然后就是一个crt
首先往回推一行,这样下指标变成连续的,发现可以对每一列的和进行递推,具体关系是\(2*f_i+f_{i+1}={n+1 \choose i+2}\)
于是这个可以在模奇数意义下求了,然后我们换个思路,从i+1推回i,发现后面2越来越多于是就不用算了
于是就CRT合并一下,就完事了!!!
AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
int s=0,t=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
while(isdigit(ch)){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
return s*t;
}
const int N=1e6+50000;
int n,m,mod,ans;
int ksm(int x,int y,int mo=mod){
if(y<0)return 0;
int ret=1;
while(y){
if(y&1)ret=ret*x%mo;
x=x*x%mo;y>>=1;
}return ret;
}
int p[N],cnt;bool vis[N];
void init(){
int sq=sqrt(max(max(n,m),mod));
fo(i,2,sq){
if(!vis[i])p[++cnt]=i;
for(int j=1;j<=cnt&&i*p[j]<=sq;j++){
vis[i*p[j]]=true;
if(i%p[j]==0)continue;
}
}
}
int pp[N],cc[N],cp;
int exgcd(int a,int b,int &x,int &y){
if(!b)return x=1,y=0,a;
int g=exgcd(b,a%b,x,y);
int xx=x;x=y;y=xx-a/b*y;
return g;
}
int inv(int x,int mo){
// if(x==0)return 1;
// return ksm(x,mod-2);
int a,b;exgcd(x,mo,a,b);
a=(a%mo+mo)%mo;return a;
}
int c[N],e[N];
int sol(int md){
int nn,mm=m>>1<<1;if(n&1)nn=n;else nn=n+1;
int now=md,ret=0;
for(int i=1;i<=cnt&&p[i]*p[i]<=now;i++)if(now%p[i]==0){
pp[++cp]=p[i];
while(now%p[i]==0){
now/=p[i];
cc[cp]++;
}
}
if(now!=1){pp[++cp]=now;cc[cp]=1;}
fo(o,1,cp){
int res=0;now=1;fo(i,1,cc[o])now*=pp[o];
if(pp[o]!=2){
// cerr<<o<<" "<<now<<endl;
int ok=0,zh=nn,cc=0;
while(zh&&zh%pp[o]==0)zh/=pp[o],cc++;
ok=res=(nn-1>>1)%now;
// cerr<<res<<" "<<ok<<" "<<now<<endl;
fo(i,1,mm){
// cerr<<i<<endl;
int p1=nn-i,p2=i+1,c1=0,c2=0;
while(p1&&p1%pp[o]==0)p1/=pp[o],c1++;
while(p2&&p2%pp[o]==0)p2/=pp[o],c2++;
cc+=c1-c2;
// cerr<<p1<<" "<<p2<<endl;
zh=zh*p1%now*inv(p2,now)%now;
// cerr<<"SB"<<endl;
ok=(zh*ksm(pp[o],cc,now)%now-ok+now)*inv(2,now)%now;
res=(res+ok)%now;
// cerr<<i<<endl;
}
}
else {
int t=cc[o];
c[0]=1;e[0]=0;while(c[0]%2==0)c[0]/=2,e[0]++;
// cerr<<c[0]<<endl;
fo(i,1,min(nn,mm+t+2)){
int p1=nn-i+1,p2=i,c1=0,c2=0;
while(p1&&p1%2==0)p1/=2,c1++;
while(p2&&p2%2==0)p2/=2,c2++;
e[i]=e[i-1]+c1-c2;
c[i]=c[i-1]*p1%now*inv(p2,now)%now;
// cerr<<c[i]<<" ";
}
// cerr<<endl;
// cerr<<m<<" "<<mm<<endl;
fo(i,0,mm){
// cerr<<i<<endl;
int bas=1;
fo(j,i+2,i+t+1){
// cerr<<i<<" "<<j<<" "<<nn<<" "<<c[j]<<" "<<e[j]<<" "<<res<<endl;
res=(res+bas*c[j]%now*ksm(2,e[j],now)%now+now)%now;
bas=bas*(-2);
}
// if(i==0)cerr<<res<<endl;
}
}
// cerr<<res<<" "<<now<<endl;
int x,y;exgcd(md/now,now,x,y);x=(x%now+now)%now;
ret=(ret+x*md/now%md*res%md)%md;
}
return (ret+1)%md;
}
signed main(){
n=read();m=min(n,read());mod=read();init();
printf("%lld\n",sol(mod));
}
T2 农民
考场上一直在想平衡树,然后寄了,其实我们直接把每个点的限制写下来,发现是区间交
就可以发现其实是树剖线段树板子,至于子树翻转,直接再维护全翻转后的区间交就行了
AC_code
#include<bits/stdc++.h>
using namespace std;
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
int s=0,t=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
while(isdigit(ch)){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
return s*t;
}
const int N=1e5+5;
const int inf=0x3f3f3f3f;
struct node{
int l,r;
node(){l=0;r=inf;}
node(int a,int b){l=a;r=b;}
node operator + (node a)const{
return node(max(l,a.l),min(r,a.r));
}
};
struct XDS{
#define ls x<<1
#define rs x<<1|1
node fi[N*4],se[N*4],nf[N*4],ns[N*4];
bool tg[N*4];
void pushup(int x){
nf[x]=nf[ls]+nf[rs];
ns[x]=ns[ls]+ns[rs];
}
void pushr(int x){
swap(nf[x],ns[x]);
tg[x]^=1;
}
void pushdown(int x){
pushr(ls);pushr(rs);tg[x]=0;
}
void ins_vl(int x,int l,int r,int ps,int v,int tp){
if(l==r){
nf[x]=node(0,v-1);
ns[x]=node(v+1,inf);
if(tp)swap(nf[x],ns[x]);
return ;
}
int mid=l+r>>1;if(tg[x])pushdown(x);
if(ps<=mid)ins_vl(ls,l,mid,ps,v,tp);
else ins_vl(rs,mid+1,r,ps,v,tp);
pushup(x);
}
void ins_tg(int x,int l,int r,int ql,int qr){
if(ql>qr)return ;
if(ql<=l&&r<=qr)return pushr(x),void();
int mid=l+r>>1;if(tg[x])pushdown(x);
if(ql<=mid)ins_tg(ls,l,mid,ql,qr);
if(qr>mid)ins_tg(rs,mid+1,r,ql,qr);
pushup(x);
}
node qry(int x,int l,int r,int ql,int qr){
if(ql>qr)return node();
if(ql<=l&&r<=qr)return nf[x];
int mid=l+r>>1;node ret;if(tg[x])pushdown(x);
if(ql<=mid)ret=ret+qry(ls,l,mid,ql,qr);
if(qr>mid)ret=ret+qry(rs,mid+1,r,ql,qr);
pushup(x);return ret;
}
#undef ls
#undef rs
}xds;
int n,m,ls[N],rs[N],fa[N],a[N],rt;bool vis[N];
int siz[N],son[N],dep[N],top[N];
int dfn[N],dfm[N],cnt,idf[N];
void dfs_fi(int x,int f){
siz[x]=1;dep[x]=dep[f]+1;fa[x]=f;
if(ls[x])dfs_fi(ls[x],x),siz[x]+=siz[ls[x]];
if(rs[x])dfs_fi(rs[x],x),siz[x]+=siz[rs[x]];
if(ls[x]&&rs[x])son[x]=siz[ls[x]]>siz[rs[x]]?ls[x]:rs[x];
else son[x]=ls[x]+rs[x];
}
void dfs_se(int x,int f){
top[x]=f;dfn[x]=++cnt;idf[cnt]=x;
if(son[x])dfs_se(son[x],f);
if(ls[x]&&ls[x]!=son[x])dfs_se(ls[x],ls[x]);
if(rs[x]&&rs[x]!=son[x])dfs_se(rs[x],rs[x]);
dfm[x]=cnt;
}
node qry(int x){
node ret;
while(x){
// cerr<<ret.l<<" "<<ret.r<<" "<<dfn[top[x]]<<" "<<dfn[x]<<endl;
ret=ret+xds.qry(1,1,n,dfn[top[x]],dfn[x]);
x=fa[top[x]];
}return ret;
}
signed main(){
n=read();m=read();
fo(i,1,n){
a[i]=read();ls[i]=read();rs[i]=read();
vis[ls[i]]=vis[rs[i]]=true;
}
fo(i,1,n)if(!vis[i])rt=i;
// cerr<<"SB"<<endl;
dfs_fi(rt,0);dfs_se(rt,rt);
// cerr<<"SB"<<endl;
fo(i,1,n){
if(ls[i])xds.ins_vl(1,1,n,dfn[ls[i]],a[i],0);
if(rs[i])xds.ins_vl(1,1,n,dfn[rs[i]],a[i],1);
}
while(m--){
int op=read(),x=read();
if(op==1){
a[x]=read();
if((ls[x]&&xds.qry(1,1,n,dfn[ls[x]],dfn[ls[x]]).l==0)||(rs[x]&&xds.qry(1,1,n,dfn[rs[x]],dfn[rs[x]]).r==inf)){
// cerr<<"SB"<<endl;
if(ls[x])xds.ins_vl(1,1,n,dfn[ls[x]],a[x],0);
if(rs[x])xds.ins_vl(1,1,n,dfn[rs[x]],a[x],1);
}
else {
if(ls[x])xds.ins_vl(1,1,n,dfn[ls[x]],a[x],1);
if(rs[x])xds.ins_vl(1,1,n,dfn[rs[x]],a[x],0);
}
}
if(op==2){
xds.ins_tg(1,1,n,dfn[x]+1,dfm[x]);
}
if(op==3){
// cerr<<"SB"<<endl;
node res=qry(x);
// cerr<<res.l<<" "<<res.r<<" "<<xds.qry(1,1,n,dfn[1],dfn[1]).l<<endl;
if(res.l<=a[x]&&a[x]<=res.r){
printf("YES\n");
}
else printf("NO\n");
}
}
}
T3 仙人掌
这次认真的再次的写圆方树,似乎了解的更多了
没啥可说的,就用分治乘法优化一下背包而已
AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
int s=0,t=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
while(isdigit(ch)){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
return s*t;
}
const int N=2e5+5;
const int mod=998244353;
int ksm(int x,int y){
int ret=1;
while(y){
if(y&1)ret=ret*x%mod;
x=x*x%mod;y>>=1;
}return ret;
}
int n,m,a[N],fd;
vector<int> d[N],e[N];
int dfn[N],low[N],cnt,sta[N],top;
vector<int> f[N];int dp[N][2],so[N],g[N];
bool cr[N];
void tarjan(int x,int fa){
dfn[x]=low[x]=++cnt;
sta[++top]=x;bool flag=true;
for(int y:d[x]){
if(y==fa&&flag){
flag=false;
continue;
}
if(!dfn[y]){
tarjan(y,x);
low[x]=min(low[x],low[y]);
if(low[y]>=dfn[x]){
++fd;if(low[y]==dfn[x])cr[fd]=true;
while(sta[top]!=y){
e[fd].push_back(sta[top]);
e[sta[top]].push_back(fd);
top--;
}top--;
e[fd].push_back(y);e[y].push_back(fd);
e[fd].push_back(x);e[x].push_back(fd);
}
}
else low[x]=min(low[x],dfn[y]);
}
}
int af[1<<20],w[1<<20];
struct poly{
vector<int> a;
poly(){a.clear();}
poly(int len){a.resize(len);}
void ntt(int lim){
fo(i,0,lim-1)if(af[i]>i)swap(a[i],a[af[i]]);
for(int t=lim>>1,d=1;d<lim;d<<=1,t>>=1)
for(int i=0;i<lim;i+=(d<<1))
fo(j,0,d-1){
int tmp=a[i+j+d]*w[t*j]%mod;
a[i+j+d]=(a[i+j]-tmp+mod)%mod;
a[i+j]=(a[i+j]+tmp)%mod;
}
}
poly operator * (poly x){
int len=0,lim=1,l1=a.size(),l2=x.a.size();
for(;lim<l1+l2;lim<<=1,len++);
fo(i,0,lim-1)af[i]=(af[i>>1]>>1)|((i&1)<<(len-1));
w[0]=1;w[1]=ksm(3,(mod-1)/lim);
fo(i,2,lim-1)w[i]=w[i-1]*w[1]%mod;
poly ret=poly(lim);
while(a.size()<lim)a.push_back(0);
while(x.a.size()<lim)x.a.push_back(0);
ntt(lim);x.ntt(lim);
fo(i,0,lim-1)ret.a[i]=a[i]*x.a[i];
w[0]=1;w[1]=ksm(w[1],mod-2);
fo(i,2,lim-1)w[i]=w[i-1]*w[1]%mod;
ret.ntt(lim);int iv=ksm(lim,mod-2);
fo(i,0,lim-1)ret.a[i]=ret.a[i]*iv%mod;
while(ret.a.size()&&!ret.a.back())ret.a.pop_back();
return ret;
}
}p[N*4];int cp;
int sol(int l,int r){
++cp;
if(r==0){
p[cp].a.clear();p[cp].a.push_back(1);
return cp;
}
if(l==r){
p[cp]=poly(3);
fo(i,0,2)p[cp].a[i]=f[so[l]][i];
return cp;
}
int mid=l+r>>1;
int ll=sol(l,mid),rr=sol(mid+1,r);
p[cp]=p[ll]*p[rr];
return cp;
}
void dfs_dp(int x,int fa){
for(int y:e[x])if(y!=fa)dfs_dp(y,x);
if(x>n){
so[0]=0;
for(int y:e[x])so[++so[0]]=y;
if(!cr[x]){
if(a[so[1]]>=1)f[x][0]=f[so[1]][a[so[1]]-1];
f[x][1]=f[so[1]][a[so[1]]];
}
else {
{
fo(i,0,so[0])fo(j,0,1)dp[i][j]=0;
dp[1][0]=1;
fo(i,1,so[0]-1){
fo(j,0,1){
if(a[so[i]]>=j+1)dp[i+1][0]=(dp[i+1][0]+dp[i][j]*f[so[i]][a[so[i]]-j-1])%mod;
if(a[so[i]]>=j)dp[i+1][1]=(dp[i+1][1]+dp[i][j]*f[so[i]][a[so[i]]-j])%mod;
}
}
fo(i,0,min(1ll,a[fa]-1)){
f[x][i+1]=(f[x][i+1]+dp[so[0]][i])%mod;
}
}
{
fo(i,0,so[0])fo(j,0,1)dp[i][j]=0;
dp[1][1]=1;
fo(i,1,so[0]-1){
fo(j,0,1){
if(a[so[i]]>=j+1)dp[i+1][0]=(dp[i+1][0]+dp[i][j]*f[so[i]][a[so[i]]-j-1])%mod;
if(a[so[i]]>=j)dp[i+1][1]=(dp[i+1][1]+dp[i][j]*f[so[i]][a[so[i]]-j])%mod;
}
}
fo(i,0,min(1ll,a[fa])){
f[x][i]=(f[x][i]+dp[so[0]][i])%mod;
}
}
}
}
else {
so[0]=0;cp=0;
for(int y:e[x])if(y!=fa)so[++so[0]]=y;
// cerr<<so[0]<<" ";
int ok=sol(1,so[0]),sz=p[ok].a.size();
// cerr<<"ok"<<" "<<p[ok].a[0]<<endl;
f[x][0]=(0>=sz?0:p[ok].a[0]);
fo(i,1,a[x])f[x][i]=(f[x][i-1]+(i>=sz?0:p[ok].a[i]))%mod;
}
// cerr<<x<<endl;
// fo(i,0,a[x])cerr<<f[x][i]<<" ";cerr<<endl;
}
signed main(){
fd=n=read();m=read();
fo(i,1,m){
int x=read(),y=read();
d[x].push_back(y);d[y].push_back(x);
}
fo(i,1,n)a[i]=min((int)d[i].size()+2,read()),f[i].resize(a[i]+1);
tarjan(1,0);
fo(i,n+1,fd)f[i].resize(3);
dfs_dp(1,0);
printf("%lld\n",f[1][a[1]]);
}
QQ:2953174821