加载中…

返回上一页

2022NOIP A层联测32

下发文件(密码为原 accoders 比赛密码)

四处行走

一看这玩意明显就是把每一种的光线分类讨论. 首先如果数量不够 n,那肯定不能. 否则:就是一个除几余几的问题.

我考场不会打 CRT,于是打了个暴力求.

点击查看代码
#pragma GCC optimize(1,2,3,"Ofast","inline","-fgcse","-fgcse-lm","-fipa-sra","-ftree-pre","-ftree-vrp","-fpeephole2","-ffast-math","-fsched-spec","unroll-loops","-falign-jumps","-falign-loops","-falign-labels","-fdevirtualize","-fcaller-saves","-fcrossjumping","-fthread-jumps","-funroll-loops","-fwhole-program","-freorder-blocks","-fschedule-insns","inline-functions","-ftree-tail-merge","-fschedule-insns2","-fstrict-aliasing","-fstrict-overflow","-falign-functions","-fcse-skip-blocks","-fcse-follow-jumps","-fsched-interblock","-fpartial-inlining","no-stack-protector","-freorder-functions","-findirect-inlining","-fhoist-adjacent-loads","-frerun-cse-after-loop","inline-small-functions","-finline-small-functions","-ftree-switch-conversion","-foptimize-sibling-calls","-fexpensive-optimizations","-funsafe-loop-optimizations","inline-functions-called-once","-fdelete-null-pointer-checks")
// 暴力出奇迹!
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define pll pair<ll,ll>
#define maxn 200001
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
	rg bool f=0;rll x=0;rg char ch=getchar(); while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10|'0'); }
ll n,m,l,r,s,ans;
vector<pll> g[maxn];
inline ll gcd(rll x,rll y) { if(!y) return x; return gcd(y,x%y); }
inline ll lcm(rll x,rll y) { return x*y/gcd(x,y); }
int main()
{
	freopen("walk.in","r",stdin); freopen("walk.out","w",stdout);
	// freopen("in.txt","r",stdin);
	n=read();m=read();l=read();r=read();
	for(rll i=1;i<=n;i++) { s=read(); for(rll j=1;j<=s;j++) g[read()].emplace_back(j,s); }
	for(rll i=1;i<=m;i++) if(g[i].size()==n)
	{
		rg bool fl=0; rll x=g[i][0].first,y=g[i][0].second;
		for(rll j=1,tx,ty,cha;j<g[i].size();j++)
		{
			tx=g[i][j].first,ty=g[i][j].second;
			if((ll)abs(x-tx)%(ll)gcd(y,ty)) { fl=1;break; }
			// if(tx>x) swap(tx,x),swap(ty,y);
			// cout<<x<<' '<<y<<' '<<tx<<' '<<ty<<endl;
			cha=x-tx; rll yz=0; while(1) if(!((y*yz+cha)%ty)) break; else yz++; x=y*yz+x; y=lcm(ty,y);
			// 暴力碾标算!
		}
		if(fl) continue;// cout<<x<<' '<<y<<endl;
		rll a=l/y,b=r/y+1; while(a*y<l) a++; while((b-1)*y>=r) b--;ans+=b-a+1; if((a-1)*y+x<l) ans--; if((b-1)*y+x>r) ans--;// cout<<ans<<endl;
	}
	write(ans);
	return 0;
}

然后居然还拿到 75 分

把这玩意改成 CRT,就可以过了. 注意要用 exCRT,因为没有保证 x 互素.

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define pll pair<ll,ll>
#define maxn 200001
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
	rg bool f=0;rll x=0;rg char ch=getchar(); while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10|'0'); }
ll n,m,l,r,s,ans;
vector<pll> g[maxn];
#define abs(x) (x<0?-x:x)
inline ll gcd(rll x,rll y) { if(!y) return x; return gcd(y,x%y); }
inline ll lcm(rll x,rll y) { return x*y/gcd(x,y); }
inline ll ksc(rll a,rll b,rll mod) { rll ans=0;a%=mod; for(rll i=b;i;i>>=1) { if(i&1) (ans+=a)%=mod; (a<<=1)%=mod; } return ans; }
inline ll exgcd(rll a,rll b,rll &x,rll &y) { if(!b) { x=1,y=0; return a; } rll ans=exgcd(b,a%b,x,y),t=x; x=y,y=t-a/b*y; return ans; }
inline ll crt(rll a1,rll b1,rll a2,rll b2)
{
	rll t=a1,ans=b1,a=t,b=a2,c=(b2-ans%b+b)%b,k,g,x,y;g=exgcd(a,b,x,y);k=b/g;
	x=ksc(x,c/g,k);ans+=x*t;t*=k;((ans%=t)+=t)%=t;
	// cout<<a1<<' '<<b1<<' '<<a2<<' '<<b2<<' '<<ans<<endl;
	return ans;
}
int main()
{
	freopen("walk.in","r",stdin); freopen("walk.out","w",stdout);
	// freopen("in.txt","r",stdin);
	n=read();m=read();l=read();r=read();
	for(rll i=1;i<=n;i++) { s=read(); for(rll j=1;j<=s;j++) g[read()].emplace_back(j,s); }
	for(rll i=1;i<=m;i++) if(g[i].size()==n)
	{
		rg bool fl=0; rll x=g[i][0].first,y=g[i][0].second;
		for(rll j=1,tx,ty,cha;j<g[i].size();j++)
		{
			tx=g[i][j].first,ty=g[i][j].second;
			if((ll)abs(x-tx)%(ll)gcd(y,ty)) { fl=1;break; }
			// if(tx>x) swap(tx,x),swap(ty,y);
			// cout<<x<<' '<<y<<' '<<tx<<' '<<ty<<endl;
			x=crt(y,x,ty,tx);// if(!~x) { fl=1;break; }
			y=lcm(ty,y);// cout<<x<<' '<<y<<endl;
		}
		if(fl) continue;// cout<<x<<' '<<y<<endl;
		rll a=l/y,b=r/y+1; while(a*y<l) a++; while((b-1)*y>r) b--;ans+=b-a+1; if((a-1)*y+x<l) ans--; if((b-1)*y+x>r) ans--;// cout<<ans<<endl;
	}
	write(ans);
	return 0;
}

鸟之诗

还是正难则反. 考虑什么时候不合法. 显然当每种约数都有这个数不乘任何数和乘这个约数的数量次方可以. 于是一个简单的容斥就出来了.

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define pll pair<ll,ll>
#define maxn 1000001
#define mod 998244353
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
	rg bool f=0;rll x=0;rg char ch=getchar(); while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10|'0'); }
// ll a[5]={ 0,1,2 };
ll m,n,cnt,jc[maxn],ny[maxn],a[maxn],b[maxn],ans=1;
// inline ll gcd(rll x,rll y) { if(!y) return x; return gcd(y,x%y); }
// inline ll lcm(rll x,rll y) { return x*y/gcd(x,y); }
inline ll ksm(rll a,rll b) { rll ans=1;a%=mod; for(rll i=b;i;i>>=1) { if(i&1) (ans*=a)%=mod; (a*=a)%=mod; } return ans; }
inline ll C(rll n,rll m) { if(n<m) return 0; return jc[n]*ny[m]%mod*ny[n-m]%mod; }
int main()
{
	freopen("air.in","r",stdin); freopen("air.out","w",stdout);
	// freopen("in.txt","r",stdin);
	jc[0]=1; for(rll i=1;i<maxn;i++) jc[i]=jc[i-1]*i%mod;
	ny[maxn-1]=ksm(jc[maxn-1],mod-2); for(rll i=maxn-2;~i;i--) ny[i]=ny[i+1]*(i+1)%mod;
	// for(rll i=1;i<=2;i++) for(rll j=1;j<=2;j++) for(rll k=1;k<=2;k++)
		// if(gcd(a[i],gcd(a[j],a[k]))==1&&lcm(a[i],lcm(a[j],a[k]))==2) cout<<a[i]<<' '<<a[j]<<' '<<a[k]<<endl,cnt++;cout<<cnt<<endl;
	m=read();n=read(); for(rll i=1;i<=m;i++) a[i]=read(); for(rll i=1;i<=m;i++) b[i]=read();
	for(rll i=1,k;i<=m;i++) if(b[i]-a[i])
	{
		k=b[i]-a[i],(ans*=(ksm(k+1,n)+(mod-ksm(k,n)<<1)%mod+ksm(k-1,n))%mod)%=mod;
	}
	write(ans);
	return 0;
}

核心共振

推式子.

写一下推的矩阵,发现 pdf 上说的 f,无论是哪个,都有 fi,j = fi-1,j-1 + fi,j-1.

那么仔细推一下,发现 \sum\limits_{i=0}^{n}f_{i,m}=f_{n+1,m+1}-1(证明留作思考,其实就是一个类似于倒三角似的东西).

阅读材料可知,在一维线段上的点数是 i,两维平面上是 \frac{i\times(i+1)}{2},三维是 \frac{i\times(i+1)\times(i+2)}{6}……

对于每维,发现其与上一维的分割数目具有累加性(证明见材料).

因此就有了 f_{n,m}=\sum\limits_{i=0}{m}C_ni.

那么推式子吧.

lucas 定理得:

f_{n,m}=\sum\limits_{i=0}^{m}C_{n\%p}^{i\%p}C_{\left\lfloor\frac{n}{p}\right\rfloor}^{\left\lfloor\frac{i}{p}\right\rfloor}.

利用一种分块的思想,对于每次出现的 \frac{i}{p},直接计算整块贡献;对于后面多出来的,单拎出来算:

f_{n,m}=\sum\limits_{i=0}^{\left\lfloor\frac{m}{p}\right\rfloor-1}C_{\left\lfloor\frac{n}{p}\right\rfloor}^{\ i}\sum\limits_{j=0}^{p-1}C_{n\%p}^{\ j}+C_{\left\lfloor\frac{n}{p}\right\rfloor}^{\left\lfloor\frac{m}{p}\right\rfloor}\sum\limits_{i=0}^{m\%p}C_{n\%p}^{\ i}.

转化到转移 f 上:

f_{n,m}=f_{\left\lfloor\frac{n}{p}\right\rfloor,\left\lfloor\frac{m}{p}\right\rfloor-1}\sum\limits_{j=0}^{p-1}C_{n\%p}^{\ j}+C_{\left\lfloor\frac{n}{p}\right\rfloor}^{\left\lfloor\frac{m}{p}\right\rfloor}\sum\limits_{i=0}^{m\%p}C_{n\%p}^{\ i}.

递归算这玩意就行了. 注意边界 m < 0 时直接返回 0 就行了.

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define pll pair<ll,ll>
#define maxn 20000001
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
	rg bool f=0;rll x=0;rg char ch=getchar(); while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10|'0'); }
ll n,m,mod,jc[maxn],ny[maxn];
inline ll ksm(rll a,rll b) { rll ans=1;a%=mod; for(rll i=b;i;i>>=1) { if(i&1) (ans*=a)%=mod; (a*=a)%=mod; } return ans; }
inline ll C(rll n,rll m) { if(n<m) return 0; return jc[n]*ny[m]%mod*ny[n-m]%mod; }
inline ll lucas(rll n,rll m) { if((!n)||(!m)) return 1; return C(n%mod,m%mod)*lucas(n/mod,m/mod)%mod; }
inline ll f(rll n,rll m)
{
	if(m<0) return 0; rll ans1=0,ans2=0;
	for(rll i=0;i<mod;i++) (ans1+=C(n%mod,i))%=mod; (ans1*=f(n/mod,m/mod-1))%=mod;
	for(rll i=0;i<=m%mod;i++) (ans2+=C(n%mod,i))%=mod; (ans2*=lucas(n/mod,m/mod))%=mod;
	// cout<<ans1<<' '<<ans2<<endl;
	return (ans1+ans2)%mod;
}
int main()
{
	freopen("dimension.in","r",stdin); freopen("dimension.out","w",stdout);
	// freopen("in.txt","r",stdin); freopen("out.txt","w",stdout);
	n=read();m=read();mod=read();
	jc[0]=1; for(rll i=1;i<min((ll)maxn,mod);i++) { jc[i]=jc[i-1]*i%mod; assert(jc[i]); }
	ny[min((ll)maxn,mod)-1]=ksm(jc[min((ll)maxn,mod)-1],mod-2); for(rll i=min((ll)maxn,mod)-2;~i;i--) ny[i]=ny[i+1]*(i+1)%mod;
	write(f(n+1,m+1)-1);
	return 0;
}

无双挑战

这个题其实和期望没有什么关系,实际上把所有的情况处理一下累加起来就行了.

暴力树剖,n2 log n 可以获得 16 分.

那么可以把每个点的 a 值放到桶里,然后从大到小按照权值从桶里取(相当于从大到小排序). 这样依次去计算每个点,是单调的即可一次算出答案.

那么怎么一次性计算出这个点到其他点的距离之和呢?可以按 dfs 序维护一棵支持区间加、区间查询的线段树,加入一个点的时候把它到根的每个点的权值都加 1,查询的时候就直接查这个点到根的权值和就行了.

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define pll pair<ll,ll>
#define maxn 800001
#define mod 998244353
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
	rg bool f=0;rll x=0;rg char ch=getchar(); while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10|'0'); }
struct node
{
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
	ll v,tag;
}t[maxn<<2];// 
ll n,m,p[maxn],sum[maxn],f[maxn],d[maxn],sz[maxn],son[maxn],dfn[maxn],top[maxn],tot,ans;
vector<ll> g[maxn],a[maxn];
inline ll ksm(rll a,rll b) { rll ans=1;a%=mod; for(rll i=b;i;i>>=1) { if(i&1) (ans*=a)%=mod; (a*=a)%=mod; } return ans; }
#define pushup(rt) t[rt].v=(t[ls(rt)].v+t[rs(rt)].v)%mod
inline void pushdown(rll rt,rll l,rll r)
{
	rll mid=l+r>>1; if(t[rt].tag)
		(t[ls(rt)].v+=t[rt].tag*(mid-l+1)%mod)%=mod,(t[rs(rt)].v+=t[rt].tag*(r-mid)%mod)%=mod,
		(t[ls(rt)].tag+=t[rt].tag)%=mod,(t[rs(rt)].tag+=t[rt].tag)%=mod,t[rt].tag=0;
}
inline void upd(rll rt,rll l,rll r,rll x,rll y,rll v)
{
	if(x<=l&&r<=y) { t[rt].v+=v*(r-l+1);t[rt].tag+=v; return; } pushdown(rt,l,r); rll mid=l+r>>1;
	if(x<=mid) upd(ls(rt),l,mid,x,y,v); if(y>mid) upd(rs(rt),mid+1,r,x,y,v); pushup(rt);
}
inline ll query(rll rt,rll l,rll r,rll x,rll y)
{
	if(x<=l&&r<=y) return t[rt].v; pushdown(rt,l,r); rll mid=l+r>>1,ans=0;
	if(x<=mid) ans+=query(ls(rt),l,mid,x,y); if(y>mid) ans+=query(rs(rt),mid+1,r,x,y); return ans;
}
inline void dfs1(rll x,rll fa)
{
	f[x]=fa;d[x]=d[fa]+1;sz[x]=1;son[x]=0;
	for(rll i=0;i<g[x].size();i++) { rll to=g[x][i]; if(to==fa) continue; dfs1(to,x);sz[x]+=sz[to]; if(sz[to]>sz[son[x]]) son[x]=to; }
}
inline void dfs2(rll x,rll fa)
{
	dfn[x]=++tot;top[x]=fa; if(son[x]) dfs2(son[x],fa);
	for(rll i=0;i<g[x].size();i++) { rll to=g[x][i]; if(dfn[to]) continue; dfs2(to,to); }
}
inline void upd(rll x,rll y)
{
	while(top[x]^top[y]) { if(d[top[x]]<d[top[y]]) swap(x,y); upd(1,1,n,dfn[top[x]],dfn[x],1); x=f[top[x]]; }
	if(d[x]>d[y]) swap(x,y); upd(1,1,n,dfn[x],dfn[y],1);
}
inline ll query(rll x,rll y)
{
	rll ans=0; while(top[x]^top[y]) { if(d[top[x]]<d[top[y]]) swap(x,y); ans+=query(1,1,n,dfn[top[x]],dfn[x]); x=f[top[x]]; }
	if(d[x]>d[y]) swap(x,y); ans+=query(1,1,n,dfn[x],dfn[y]); return ans;
}
int main()
{
	freopen("challenge.in","r",stdin); freopen("challenge.out","w",stdout);
	// freopen("in.txt","r",stdin);
	n=read();m=read(); for(rll i=1;i<=n;i++) p[i]=read();
	for(rll i=1,u,v;i<n;i++) g[u=read()].emplace_back(v=read()),g[v].emplace_back(u);
	dfs1(1,0);dfs2(1,1); for(rll i=1;i<=n;i++) a[p[i]].emplace_back(i),sum[p[i]]+=d[i];
	for(rll i=m,s=0,cnt=0;i;i--)
	{
		for(rll j=0;j<a[i].size();j++) (ans+=(m-p[a[i][j]]+mod)*(s+cnt*d[a[i][j]]%mod-(query(1,a[i][j])<<1)+mod)%mod)%=mod;
		(s+=sum[i])%=mod;(cnt+=(ll)a[i].size())%=mod; for(rll j=0;j<a[i].size();j++) upd(1,a[i][j]);
	}
	write((ans*ksm(n*(n-1),mod-2)%mod+mod)%mod);
	return 0;
}
posted @ 2022-11-21 18:03  1Liu  阅读(17)  评论(1编辑  收藏  举报