多校省选模拟2


T1 守序划分问题

记划分后的集合为\(A_i\),全集\(U=\{i|1<=i<=m\}\)

题目限制等价于,一种集合划分合法,当且仅当\(\forall S\subset U且S!=\varnothing,\min A_{i\in S}<\max A_{j \not\in S}\)

证明充分性就构造然后归纳一下

将所有集合按min升序,设已经处理完 \(A_{p_{i-1}}\)且合法

由于\(\min A_{j\in[i,m]}=\min A_i\),根据条件可知,存在\(j\in[1,i-1]\)满足\(\max A_j>\min A_i\)

必要性是显然的

然后可以dp了,f[i][j][k]设前 i 个数划分到 j 个集合,有 k 个集合还未闭合

转移就分四种情况,是否闭合集合和是否新开集合

\[f[i][j][k]=f[i-1][j-1][k]+f[i-1][j-1][k-1]+(k+1)*f[i-1][j][k+1]+k*f[i-1][j][k] \]

还要注意边界

T2 欧拉函数

然而并没有写正解

加法还是比较好写的,就扫一遍\(p_i<=\sqrt {\sum a_j}\),复杂度是\(O(q\frac{\sqrt {nw}}{\log \sqrt {nw}})\)

对于乘法,每个数把质因数存进bitset里,每个线段树节点存一个bitset,然后就单点修改区间查询

bitset还有俩nb的函数,叫\(\_Find\_first,\_Find\_next\),找第一个1和下一个1

T3 点整的上圆

Min_25筛还没学,,,

代码

T1

#include
using namespace std;
#define il inline
#define int long long
const int N=5e2+11;
const int mod=998244353;
int n,m;
int f[2][N][N];
il void md(int &x){if(x>=mod)x-=mod;return;}
il int read()
{
	int s=0;
	char ch=getchar();
	while(ch>'9'||ch<'0')ch=getchar();
	while(ch>='0'&&ch<='9')s=(s<<1)+(s<<3)+(ch^48),ch=getchar();
	return s;
}
signed main()
{
	freopen("partition.in","r",stdin);
	freopen("partition.out","w",stdout);
	n=read(),m=read();
	f[0][0][0]=1;
	bool now,last;
	for(int i=1;i<=n;++i)
	{
		now=i&1,last=now^1;
		for(int j=1;j<=m;++j)
		{
			for(int k=0;k<=j;++k)
			{
				md(f[now][j][k]+=f[last][j-1][k]);
				if(k) md(f[now][j][k]+=f[last][j-1][k-1]);
				md(f[now][j][k]+=(k+1)*f[last][j][k+1]%mod);
				md(f[now][j][k]+=k*f[last][j][k]%mod);
			}
			if(i!=n) f[now][j][0]=0;
		}
		memset(f[last],0,sizeof(f[last]));
	}
	cout<

T2

#include
using namespace std;
#define il inline
#define int long long
const int B=4205;
const int N=4e4+11;
const int M=5e4+11;
const int mod=1e9+7;
struct tree{int l,r;bitset bit;}tre[4*M];
int n,q;
bool fp[N];
int p[N],num,inv[N];
int a[M],tre1[M],tre2[M];
vector vct[N];
bitset bit;
int fm(int x,int y){int ans=1;for(;y;y>>=1,x=x*x%mod)if(y&1)ans=ans*x%mod;return ans;}
void insert1(int x,int val){for(;x<=n;x+=(x&-x))tre1[x]+=val;return;}
int query1(int x){int sum=0;for(;x;x-=(x&-x))sum+=tre1[x];return sum;}
void insert2(int x,int val){for(;x<=n;x+=(x&-x))tre2[x]=tre2[x]*val%mod;return;}
int query2(int x){int sum=1;for(;x;x-=(x&-x))sum=sum*tre2[x]%mod;return sum;}
il int read()
{
	int s=0;
	char ch=getchar();
	while(ch>'9'||ch<'0')ch=getchar();
	while(ch>='0'&&ch<='9')s=(s<<1)+(s<<3)+(ch^48),ch=getchar();
	return s;
}
void pre()
{
	fp[0]=fp[1]=1;
	inv[0]=inv[1]=1;
	for(int i=0;i>1;
	build(i<<1,l,mid);
	build(i<<1|1,mid+1,r);
	tre[i].bit=tre[i<<1].bit|tre[i<<1|1].bit;
	return;
}
void insert(int i,int x,int val)
{
	if(tre[i].l==tre[i].r){tre[i].bit.reset();for(int x : vct[val]) tre[i].bit[x]=1;return;}
	int mid=(tre[i].l+tre[i].r)>>1;
	if(x<=mid) insert(i<<1,x,val);
	else insert(i<<1|1,x,val);
	tre[i].bit=tre[i<<1].bit|tre[i<<1|1].bit;
	return;
}
bitset query(int i,int l,int r)
{
	if(tre[i].l>=l&&tre[i].r<=r) return tre[i].bit;
	bitset ans;ans.reset();
	int mid=(tre[i].l+tre[i].r)>>1;
	if(l<=mid) ans=query(i<<1,l,r);
	if(r>mid) ans|=query(i<<1|1,l,r);
	return ans;
}
int get_ans1(int l,int r)
{
	int sum=query1(r)-query1(l-1);
	int ans=sum%mod;
	int sq=sqrt(sum);
	for(int i=1;i<=num;++i)
	{
		if(p[i]>sq) break;
		if(sum%p[i]==0)
		{
			ans=ans*inv[p[i]]%mod*(p[i]-1)%mod;
			while(sum%p[i]==0)sum/=p[i];
		}
	}
	if(sum>1) ans=ans*fm(sum,mod-2)%mod*(sum-1)%mod;
	return ans;
}
int get_ans2(int l,int r)
{
	int ans=query2(r)*fm(query2(l-1),mod-2)%mod;
	bit.reset(),bit=query(1,l,r);
	for(int i=bit._Find_first();i