天天看点

【NOIp2019模拟】—题解

T1

很显然就是钦定一些质数的出现次数在一个范围之间的所有情况

就是枚举几个不满足上下界的条件

就得到每个质因子可以选择的范围

就可以随便算方案数了

实际上上下界不满足都只会让系数 − 1 -1 −1

把上下界一个不满足的情况分开讨论就可以做到 O ( 3 p n u m ) O(3^{p_{num}}) O(3pnum​)次方了

#include<bits/stdc++.h>
using namespace std;
#define gc getchar
inline int read(){
	char ch=gc();
	int res=0,f=1;
	while(!isdigit(ch))f^=ch=='-',ch=gc();
	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
	return f?res:-res;
}
#define re register
#define pb push_back
#define cs const
#define pii pair<int,int>
#define fi first
#define se second
#define ll long long
#define poly vector<int>
#define bg begin
cs int mod=998244353;
inline int add(int a,int b){return (a+=b)>=mod?a-mod:a;}
inline void Add(int &a,int b){(a+=b)>=mod?(a-=mod):0;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
inline void Dec(int &a,int b){(a-=b)<0?(a+=mod):0;}
inline int mul(int a,int b){return 1ll*a*b>=mod?1ll*a*b%mod:a*b;}
inline int mul(int a,int b,int Mod){return 1ll*a*b>=Mod?1ll*a*b%Mod:a*b;}
inline void Mul(int &a,int b){a=mul(a,b);}
inline int ksm(int a,int b){
	int res=1;
	for(;b;b>>=1,a=mul(a,a))(b&1)&&(res=mul(res,a));return res;
}
inline void chemx(ll &a,ll b){a<b?a=b:0;}
inline void chemn(ll &a,ll b){a>b?a=b:0;}
inline ll ksm(ll a,ll b,cs ll &mod){
	ll res=1;
	for(;b;b>>=1,a=mul(a,a,mod))if(b&1)res=mul(res,a,mod);
	return res;
}
cs int N=1000005,M=N-5;
bool isp[N];
int pr[N],tot;
inline void init(){
	for(int i=2;i<=M;i++){
		if(!isp[i])pr[++tot]=i;
		for(int j=1;j<=tot&&i*pr[j]<=M;j++){
			isp[i*pr[j]]=1;
			if(i%pr[j]==0)break;
		}
	}
}
inline bool Miller_Rabin(ll x){
	ll mod=x;
	if(x<=M)return !isp[x];
	if(!(x&1))return false;
	if((x%3==0)||(x%5==0)||(x%7==0))return false;
	ll t=x-1,s=0;
	while(!(t&1))t>>=1,s++;
	for(int i=1;i<=20&&pr[i]<x;i++){
		ll k=ksm(pr[i],t,mod),pre=k;
		if(x%pr[i]==0)return false;
		for(int j=0;j<s;j++){
			k=mul(k,k,mod);
			if(k==1&&pre!=1&&pre!=x-1)return false;
			pre=k;
		}
		if(k!=1)return false;
	}
	return true;
}
int c[N],ans,cnt;
inline void calc(int coef,int coef2,int siz){
	if(siz&1)Add(ans,mul(coef2,ksm(2,coef)-1));
	else Dec(ans,mul(coef2,ksm(2,coef)-1));
}
void dfs(int pos,int coef,int coef2,int siz){
	if(pos==cnt+1)return calc(coef,coef2,siz);
	dfs(pos+1,mul(coef,c[pos]+1,mod-1),coef2,siz);
	dfs(pos+1,mul(coef,c[pos],mod-1),mul(coef2,2),siz+1);
	if(c[pos]>1)dfs(pos+1,mul(coef,c[pos]-1,mod-1),coef2,siz+2);
}
int main(){
	init();
	ll m;
	scanf("%lld",&m);
	for(int i=1;i<=tot;i++){
		if(m%pr[i]==0){
			int tt=0;
			while(m%pr[i]==0)tt++,m/=pr[i];
			c[++cnt]=tt;
		}
	}
	if(m>1){
		if(Miller_Rabin(m))c[++cnt]=1;
		else{
			int x=sqrt(m);
			if(1ll*x*x==m){
				c[++cnt]=2;
			}
			else{
				c[++cnt]=1,c[++cnt]=1;
			}
		}
	}
	dfs(1,1,1,1);
	cout<<ans;
}
           

T2

设 k i k_i ki​第 i i i个选的个数, f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示前 i i i个,填了 j j j个, ∑ a m a x ( 0 , c a − k a ) − m a x ( 0 , k a − c a ) / 4 = k \sum_amax(0,c_a-k_a)-max(0,k_a-c_a)/4=k ∑a​max(0,ca​−ka​)−max(0,ka​−ca​)/4=k的方案数,步长乘方案数就是答案

最后由于去重是 ( ∑ k i ) ! ∏ k i ! \frac{(\sum k_i)!}{\prod k_i!} ∏ki​!(∑ki​)!​

下面的系数中间边乘维护

边界情况有点奇怪,反正我是没搞懂

#include<bits/stdc++.h>
using namespace std;
#define gc getchar
inline int read(){
	char ch=gc();
	int res=0,f=1;
	while(!isdigit(ch))f^=ch=='-',ch=gc();
	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
	return f?res:-res;
}
#define re register
#define pb push_back
#define cs const
#define pii pair<int,int>
#define fi first
#define se second
#define ll long long
#define poly vector<int>
#define bg begin
cs int mod=1e9+7;
inline int ksm(int a,int b,int res=1){
	for(;b;b>>=1,a=1ll*a*a%mod)(b&1)&&(res=1ll*res*a%mod);return res;
}
inline void chemx(int &a,int b){a<b?a=b:0;}
inline void chemn(int &a,int b){a>b?a=b:0;}
cs int N=12,M=405,C=1605;
int f[N][M][C],q[N],c[N],p[C],fac[C],ifac[C],Q,tot,mx,n;
inline void init(){
	fac[0]=ifac[0]=1;
	for(int i=1;i<C;i++)fac[i]=1ll*fac[i-1]*i%mod;
	ifac[C-1]=ksm(fac[C-1],mod-2);
	for(int i=C-2;i;i--)ifac[i]=1ll*ifac[i+1]*(i+1)%mod;
}
int main(){
	init();
	n=read();
	for(int i=1;i<=n;i++)q[i]=read(),Q+=q[i];
	Q=ksm(Q,mod-2);
	for(int i=1;i<=n;i++)q[i]=1ll*q[i]*Q%mod;
	for(int i=1;i<=n;i++)c[i]=read(),tot+=c[i];
	f[0][tot][0]=1,mx=tot*4;
	for(int i=1;i<=n;i++){
		for(int t=1,j=0;j<=mx;j++,(t=1ll*t*q[i]%mod))p[j]=1ll*ifac[j]*t%mod;
		for(int j=0;j<=tot;j++)for(int k=0;k<=mx;k++)
		if(f[i-1][j][k]){
			int pt=f[i-1][j][k];
			for(int l=0;l<=mx-k;l++){
				int del=c[i];
				if(l<c[i])del+=l-c[i];
				else del+=(l-c[i])/4;
				if(j>=del)(f[i][j-del][k+l]+=1ll*pt*p[l]%mod)%=mod;
			}
		}
	}
	int res=1;
	for(int j=1;j<=mx;j++){
		int now=0;
		for(int i=1;i<=tot;i++)
		(now+=f[n][i][j])%=mod;
		(res+=1ll*fac[j]*now%mod)%=mod;
	}
	cout<<res;
}
           

T3

考场用随机化贪心骗了 45 p t s 45pts 45pts

实际上把式子拆开

可以发现我们只需要把两两点匹配使得点积和最大

这是一个二分图最大权匹配

结果卡了费用流做法。。。。

只能写 K M KM KM,还只有非递归版能过

O r z Orz Orz了一波仲爺的板子

#include<bits/stdc++.h>
using namespace std;
#define gc getchar
inline int read(){
	char ch=gc();
	int res=0,f=1;
	while(!isdigit(ch))f^=ch=='-',ch=gc();
	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
	return f?res:-res;
}
#define re register
#define pb push_back
#define cs const
#define pii pair<int,int>
#define fi first
#define se second
#define ll long long
#define poly vector<int>
#define bg begin
cs int mod=998244353;
inline int add(int a,int b){return (a+=b)>=mod?a-mod:a;}
inline void Add(int &a,int b){(a+=b)>=mod?(a-=mod):0;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
inline void Dec(int &a,int b){(a-=b)<0?(a+=mod):0;}
inline int mul(int a,int b){return 1ll*a*b>=mod?1ll*a*b%mod:a*b;}
inline int mul(int a,int b,int Mod){return 1ll*a*b>=Mod?1ll*a*b%Mod:a*b;}
inline void Mul(int &a,int b){a=mul(a,b);}
inline int ksm(int a,int b,int res=1){
	for(;b;b>>=1,a=mul(a,a))(b&1)&&(res=mul(res,a));return res;
}
inline void chemx(int &a,int b){a<b?a=b:0;}
inline void chemn(int &a,int b){a>b?a=b:0;}
cs int N=505;
int a[N][N],n;
namespace KM{
	int wx[N],wy[N],px[N],py[N],vx[N],vy[N],path[N],id,mn[N];
	#define calc(x,y) ((wx[(x)]+wy[(y)]-a[(x)][(y)]))
	inline void solve(){
		for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)chemx(wx[i],a[i][j]);
		for(int i=1;i<=n;i++){
			vx[i]=++id,path[i]=0;
			for(int j=1;j<=n;j++)mn[j]=i;
			while(!px[i]){
				int oy=0;
				for(int j=1;j<=n;j++)
				if(vy[j]!=id&&(!oy||(calc(mn[j],j)<calc(mn[oy],oy))))oy=j;
				int ox=mn[oy],val=calc(ox,oy);
				for(int j=1;j<=n;j++){
					if(vx[j]==id)wx[j]-=val;
					if(vy[j]==id)wy[j]+=val;
				}
				if(!py[oy]){
					while(ox){
						py[oy]=ox;
						swap(oy,px[ox]);
						ox=path[ox];
					}
				}
				else{
					int curx=py[oy];path[curx]=ox;
					vx[curx]=vy[oy]=id;
					for(int j=1;j<=n;j++)
					if(vy[j]!=id&&(calc(mn[j],j))>calc(curx,j))mn[j]=curx;
				}
			}
		}
		cout<<"Yes\n";
		for(int i=1;i<=n;i++)cout<<px[i]<<" ";
	}
}
struct pt{
	int x,y;
	pt(int _x=0,int _y=0):x(_x),y(_y){}
	friend inline int operator ^(cs pt &a,cs pt &b){
		return a.x*b.x+a.y*b.y;
	}
}p[N],v[N];
int main(){
	n=read();
	for(int i=1;i<=n;i++)p[i].x=read(),p[i].y=read();
	for(int i=1;i<=n;i++)v[i].x=read(),v[i].y=read();
	for(int i=1;i<=n;i++)
	for(int j=1;j<=n;j++)a[i][j]=p[i]^v[j];
	KM::solve();
}