省选模拟37

A. 小 F 与游戏

打表出奇迹

\(k=1\) 时答案为 \(2^n-2\)

\(k=n\) 时答案为卡特兰数

于是大胆猜测答案和 \(2\) 的次方和卡特兰数相关

其他情况下答案为 \(2^{n-k-1}(\binom{n+k-2}{k-1}-\binom{n+k-2}{k-2})\)

再加一个表

 1
 1  1
 2  2  2
 4  6  5  5
 8 16 18 14 14
16 40 56 56 42 42
Code
#include<bits/stdc++.h>
#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define meow(args...) fprintf(stderr,args)
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,k,mod;
int fac[1000010],inv[1000010];
inline int C(int n,int m){return fac[n]*inv[m]%mod*inv[n-m]%mod;}
inline int qpow(int x,int k){
	int res=1,base=x;
	while(k){if(k&1) res=res*base%mod;base=base*base%mod;k>>=1;}
	return res;
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("game.in","r",stdin);
	freopen("game.out","w",stdout);
	n=read(),k=read(),mod=read();
	inv[0]=fac[0]=1;for(int i=1;i<=1000000;i++) fac[i]=fac[i-1]*i%mod;
	inv[1000000]=qpow(fac[1000000],mod-2);for(int i=1000000-1;i;i--) inv[i]=inv[i+1]*(i+1)%mod;
	if(k==1) printf("%lld\n",qpow(2,n-2)),exit(0);
	if(n==k) printf("%lld\n",(C(2*n-2,n-1)-C(2*n-2,n-2)+mod)%mod),exit(0);
	printf("%lld\n",qpow(2,n-k-1)*(C(n+k-2,k-1)-C(n+k-2,k-2)+mod)%mod);
	return 0;
}

B. 小 Z 与函数

不难发现 \(\text{swap}\) 的次数,就是顺序对的个数

于是只用考虑有哪些位置需要去交换

加入一个位置后,交换完后这个位置的值一定是最小值,此时不会产生贡献

考虑这个位置什么时候会产生贡献

如果是排列的话,这个位置肯定会在下一个比他大的数加入时被交换

如果有相同的就需要去考虑把所有相同的值都替换掉时的位置

此时只需要记录上一个值产生贡献的位置,然后再从这个位置往后找

这个可以用线段树上二分实现,又因为是区间查所以复杂度应该是两个 \(\log\)

不过常数要小

Code
#include<bits/stdc++.h>
#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define lowbit(x) x&-x
#define lson rt<<1
#define rson rt<<1|1
#define meow(args...) fprintf(stderr,args)
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int T,n,ans;
int a[200010],c[200010];
int BIT[200010],lst[200010];
bool vis[200010];
multiset<int>S;
struct seg{int mx;}st[200010*4];
inline void ins(int x){for(;x<=n;x+=lowbit(x)) BIT[x]++;}
inline int query(int x){int res=0;for(;x;x-=lowbit(x)) res+=BIT[x];return res;}
void build(int rt,int l,int r){
	if(l==r) return st[rt].mx=a[l],void();
	int mid=(l+r)>>1;
	build(lson,l,mid);
	build(rson,mid+1,r);
	st[rt].mx=max(st[lson].mx,st[rson].mx);
}
int query(int rt,int l,int r,int L,int R,int k){
	if(l==r) return l;if(st[rt].mx<=k) return n+1;
	int mid=(l+r)>>1,v=n+1;
	if(L<=l&&r<=R){
		if(st[lson].mx>k) return query(lson,l,mid,L,R,k);
		return query(rson,mid+1,r,L,R,k);
	}
	if(L<=mid&&st[lson].mx>k){
		v=query(lson,l,mid,L,R,k);
		if(v!=n+1) return v;
	}
	if(R>mid&&st[rson].mx>k){
		v=query(rson,mid+1,r,L,R,k);
		if(v!=n+1) return v;
	}
	return n+1;
}
inline void solve(){
	n=read();ans=0;memset(BIT,0,sizeof(BIT));memset(vis,0,sizeof(vis));memset(c,0,sizeof(c));memset(lst,0,sizeof(lst));S.clear();
	for(int i=1;i<=n;i++) a[i]=read();build(1,1,n);
	for(int i=1,v,pos;i<=n;i++){
		v=query(a[i]-1);ans+=v;ans+=c[i];
		S.insert(a[i]);pos=max(i,lst[*S.begin()])+1;
		if(pos<=n){pos=query(1,1,n,pos,n,*S.begin());c[pos]++;}
		printf("%lld ",ans);
		lst[*S.begin()]=pos;
		if(!vis[a[i]]) ins(a[i]),vis[a[i]]=1;
	}
	puts("");
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("function.in","r",stdin);
	freopen("function.out","w",stdout);
	T=read();while(T--) solve();
	return 0;
}

C. 小 W 与骑士

考虑容斥,设 \(f_i\) 表示第一个到达的障碍点是 \(i\) 的方案数

然后可以根据的平面向量基本定理列出方程,解得唯一解

再用组合数算出方案数,就能得到从 \((0,0)\) 到达某个点的方案数

再根据定义,减去从其他障碍点到这个障碍点的方案数

再考虑向量平行的情况

可以直接转成 \(1\)\(dp\)

注意要判掉 \(-1\) 的情况,这里比较懒直接写的判断是否在一条线上

还有一些细节,可以看代码

Code
#include<bits/stdc++.h>
#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define mod 1000000007
#define meow(args...) fprintf(stderr,args)
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int T,n,x,y,ax,ay,bx,by;
int fac[1000010],inv[1000010],f[1010];
bool vis[1010];
struct node{int x,y;}L[510];
inline int C(int n,int m){return fac[n]*inv[m]%mod*inv[n-m]%mod;}
inline int calc(int x,int y){
	int p,q;
	q=(ax*y-ay*x)/(ax*by-bx*ay);
	if(q*(ax*by-bx*ay)!=(ax*y-ay*x)) return 0;
	p=(x-q*bx)/ax;
	if(p*ax!=(x-q*bx)) return 0;
	if(p<0||q<0) return 0;
	return C(p+q,p);
}
inline int qpow(int x,int k){
	int res=1,base=x;
	while(k){if(k&1) res=res*base%mod;base=base*base%mod;k>>=1;}
	return res;
}
inline void rev(){
	swap(x,y);swap(ax,ay);swap(bx,by);
	for(int i=1;i<=n;i++) swap(L[i].x,L[i].y);
}
int dfs(int x){
	if(vis[x]) return f[x];vis[x]=1;
	int sum=calc(L[x].x,L[x].y);if(!sum) return f[x]=0;
	for(int i=1,px,py,v;i<=n;i++) if(i!=x){
		px=L[x].x-L[i].x;
		py=L[x].y-L[i].y;
		v=calc(px,py);if(!v) continue;
		sum=(sum-v*dfs(i)%mod+mod)%mod;
	}
	return f[x]=sum;
}
namespace task{
	int f[510];
	bool ban[510];
	void main(){
		memset(ban,0,sizeof(ban));memset(f,0,sizeof(f));
		if(ax*bx<0) return puts("-1"),void();
		if(ax<0){
			x=-x,y=-y,ax=-ax,ay=-ay,bx=-bx,by=-by;
			for(int i=1;i<=n;i++) L[i].x=-L[i].x,L[i].y=-L[i].y;
		}
		for(int i=1;i<n;i++) if(L[i].x>0) if(1.0*ay/ax==1.0*L[i].y/L[i].x) ban[L[i].x]=1;
		f[0]=1;
		for(int i=0;i<=x;i++) if(!ban[i]){
			(f[i+ax]+=f[i])%=mod;
			if(ax!=bx) (f[i+bx]+=f[i])%=mod;
		}
		printf("%lld\n",f[x]);
	}
}
inline void solve(){
	x=read(),y=read(),n=read();
	ax=read(),ay=read(),bx=read(),by=read();
	for(int i=1;i<=n;i++) L[i].x=read(),L[i].y=read();n++;L[n].x=x,L[n].y=y;
	if(!ax) rev();
	if(!ax) return puts("0"),void();
	if((1.0*ay/ax==1.0*by/bx)){
		if(1.0*y/x==1.0*ay/ax) return task::main(),void();
		return puts("0"),void();
	}
	memset(f,0,sizeof(f));memset(vis,0,sizeof(vis));
	printf("%lld\n",dfs(n));
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("knight.in","r",stdin);
	freopen("knight.out","w",stdout);
	inv[0]=fac[0]=1;for(int i=1;i<=1000000;i++) fac[i]=fac[i-1]*i%mod;
	inv[1000000]=qpow(fac[1000000],mod-2);for(int i=1000000-1;i;i--) inv[i]=inv[i+1]*(i+1)%mod;
	T=read();while(T--) solve();
	return 0;
}
posted @ 2022-03-24 18:42  Max_QAQ  阅读(85)  评论(2编辑  收藏  举报