省选模拟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;
}