【2020省选模拟】题解

T1

神题

显然先容斥lr+1l或r+1作为下界
设下界和为ss
假设最后总和为xx
就相当于a1+a2+a3....+an=xa_1+a_2+a_3....+a_n=x解一个方程组
解都为正整数的方案为(xs1n1){x-s-1\choose n-1}
要求正整数把l,rl,r都减一即可
答案即为x>s(xs1n1)[x]=x>0(x1n1)[x+s]=x>=0(xn1)[x+s+1]\sum_{x>s}{x-s-1\choose n-1}[x合法]=\sum_{x>0}{x-1\choose n-1}[x+s合法]=\sum_{x>=0}{x\choose n-1}[x+s+1合法]
为了方便将s1s加1变成x>=0(xn1)[x+s]\sum_{x>=0}{x\choose n-1}[x+s合法]

考虑用范德蒙德恒等式拆开(范德蒙德恒等式对广义组合数仍成立)
这个组合数(xn1)=i(x+si)(sn1i){x\choose n-1}=\sum_{i}{x+s\choose i}{-s\choose n-1-i}

这时候就只需要算ix>=s(xi)[x]\sum_{i}\sum_{x>=s}{x\choose i}[x合法]
再拆开考虑每一位的贡献(xi)=j(xdDkji)(dDkj){x\choose i}=\sum_{j}{x-d*D^k\choose j-i}{d*D^k\choose j}
然后用数位dpdp求出这样个东西的贡献
预处理转移时组合数系数前后缀和加快转移

总复杂度O(2nn2500)O(2^nn^2*500)

不知道为什么跑这么慢。。。。

#include<bits/stdc++.h>
using namespace std;
#define cs const
#define re register
#define pb push_back
#define pii pair<int,int>
#define ll long long
#define fi first
#define se second
#define bg begin
cs int RLEN=1<<20|1;
inline char gc(){
    static char ibuf[RLEN],*ib,*ob;
    (ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
    return (ib==ob)?EOF:*ib++;
}
inline int read(){
    char ch=gc();
    int res=0;bool 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;
}
inline int readstr(int *s){
	int top=0;char ch=gc();
	while(isspace(ch))ch=gc();
	while(!isspace(ch))s[++top]=ch-'0',ch=gc();
	return top;
}
template<class tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
template<class tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
cs int mod=1e9+7;
inline int add(int a,int b){return (a+=b)>=mod?(a-mod):a;}
inline int dec(int a,int b){a-=b;return a+(a>>31&mod);}
inline int mul(int a,int b){static ll r;r=1ll*a*b;return (r>=mod)?(r%mod):r;}
inline void Add(int &a,int b){(a+=b)>=mod?(a-=mod):0;}
inline void Dec(int &a,int b){a-=b,a+=a>>31&mod;}
inline void Mul(int &a,int b){static ll r;r=1ll*a*b;a=(r>=mod)?(r%mod):r;}
inline int ksm(int a,int b,int res=1){for(;b;b>>=1,Mul(a,a))(b&1)&&(Mul(res,a),1);return res;}
inline int Inv(int x){return ksm(x,mod-2);}
inline int fix(int x){return (x<0)?x+mod:x;}
cs int N=15,M=515;
int D,n,C[M][M][N],pre[M][M][N],suf[M][M][N],ok[M];
int inv[M];
inline void readIn(vector<int> &a){
	static int num[M*10],len;
	len=readstr(num);
	reverse(num+1,num+len+1);
//	for(int i=1;i<=len;i++)cout<<num[i]<<" . ";puts("");
	while(len){
		int s=0;
		for(int i=len;i;i--)
			s=s*10+num[i],num[i]=s/D,s%=D;
		a.pb(s);//cout<<s<<" ";
		while(len&&num[len]==0)len--;
	}//puts("");
}
struct bignum{
	vector<int> a;
	bignum(){a.clear();}
	inline void clear(){a.clear();}
	void read(){
		readIn(a);
	}
	inline void del(){while(a.size()&&!a.back())a.pop_back();}
	void operator ++(){
		a.pb(0);a[0]++;
		for(int i=0;i<a.size()-1;i++)
		if(a[i]>=D)a[i]-=D,a[i+1]++;
		del();
	}
	void operator --(){
		if(!a.size())a.pb(0);a[0]--;
		for(int i=0;i<(int)a.size()-1;i++)
		if(a[i]<0)a[i]+=D,a[i+1]--;
		del();
	}
	inline int len()cs{return a.size();}
	friend inline bignum operator +(cs bignum &a,cs bignum &b){
		bignum c;int len=max(a.len(),b.len());
		c.a.resize(len);
		for(int i=0;i<len;i++)c.a[i]=(a.len()>i?a.a[i]:0)+(b.len()>i?b.a[i]:0);
		c.a.pb(0);
		for(int i=0;i<len;i++)if(c.a[i]>=D)c.a[i]-=D,c.a[i+1]++;
		c.del();return c;
	}
	inline int pos(int x){return a.size()>x?a[x]:0;}
	inline int val(){int res=0;for(int i=(int)a.size()-1;~i;i--)res=add(mul(res,D),a[i]);return res;}
};
bignum L[N],R[N],dn;
inline void init_inv(){
	inv[0]=inv[1]=1;
	for(int i=2;i<M;i++)inv[i]=mul(mod-mod/i,inv[mod%i]);
}
int g[2][N],f[2][N],s[N];
inline int calc(){
	memset(f,0,sizeof(f));
	memset(s,0,sizeof(s));
	f[1][0]=1;int cur=0;
	for(int i=0;i<=510;i++){
		int lim=dn.pos(i);
		memcpy(g,f,sizeof(g));
		memset(f,0,sizeof(f));
		for(int x=0;x<n;x++)if(g[0][x]||g[1][x]){
			int now=add(g[0][x],g[1][x]);
			for(int y=0;x+y<n;y++){
				if(lim)Add(f[0][x+y],mul(now,pre[i][lim-1][y]));
				if(lim+1<D){
					Add(f[1][x+y],mul(now,suf[i][lim+1][y]));
					if(i+1>=dn.len())Add(s[x+y],mul(now,suf[i][lim+1][y]));
				}
				for(int t=0;t<2;t++)
				Add(f[t][x+y],mul(g[t][x],C[i][lim][y]));
				if(i+1==dn.len())Add(s[x+y],mul(g[1][x],C[i][lim][y]));
			}
		}
	}
	int v=dec(0,dn.val()),res=0,c=1;
	for(int i=0;i<n;i++){
		if(i)c=mul(c,mul(dec(v,i-1),inv[i]));
		Add(res,mul(s[n-1-i],c));
	}
	return res;
}
int main(){
	#ifdef Stargazer
	freopen("lx.in","r",stdin);
	#endif	
	n=read(),D=read(),init_inv();
	for(int i=0;i<D;i++)ok[i]=read();
	for(int i=1;i<=n;i++)L[i].read(),R[i].read(),--L[i];
	for(int i=0,pw=1,mt;i<=510;i++,Mul(pw,D)){
		for(int d=0;d<D;d++)if(ok[d]){
			C[i][d][0]=1,mt=mul(pw,d);
			for(int j=1;j<=n;j++)
			C[i][d][j]=mul(C[i][d][j-1],mul(dec(mt+1,j),inv[j]));
		}
		for(int j=0;j<=n;j++)pre[i][0][j]=C[i][0][j];
		for(int d=1;d<D;d++)
		for(int j=0;j<n;j++)
			pre[i][d][j]=add(pre[i][d-1][j],C[i][d][j]);//,cout<<pre[i][d][j]<<'\n';;
		for(int j=0;j<=n;j++)suf[i][D-1][j]=C[i][D-1][j];
		for(int d=D-2;~d;d--)
		for(int j=0;j<n;j++)
			suf[i][d][j]=add(suf[i][d+1][j],C[i][d][j]);//cout<<suf[i][d][j]<<'\n';
	}
	int res=0;
	for(int s=0;s<(1<<n);s++){
		dn.clear();int siz=0;
		for(int i=0;i<n;i++)
		if(s&(1<<i))siz++,dn=dn+R[i+1];
		else dn=dn+L[i+1];
	//	for(int i=0;i<dn.a.size();i++)cout<<dn.a[i]<<" ";puts("");
		++dn;
		if(siz&1)Dec(res,calc());
		else Add(res,calc());
	}
	cout<<res<<'\n';
}

T2:

预处理每两点间距离枚举两条边分类讨论贡献即可
stdstd没考虑一条边的情况。。。

#include<bits/stdc++.h>
using namespace std;
#define cs const
#define re register
#define pb push_back
#define pii pair<int,int>
#define ll long long
#define fi first
#define se second
#define bg begin
cs int RLEN=1<<20|1;
inline char gc(){
    static char ibuf[RLEN],*ib,*ob;
    (ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
    return (ib==ob)?EOF:*ib++;
}
inline int read(){
    char ch=gc();
    int res=0;bool 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;
}
template<class tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
template<class tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
cs int N=5005;
int dis[N][N];
vector<pii> e[N];
struct edge{
	int u,v,w;
}E[N];
int n,m,ans,vis[N];
priority_queue<pii,vector<pii>,greater<pii> > q;
inline void dijkstra(int str,int *dis){
	memset(vis,0,sizeof(int)*(n+1));
	dis[str]=0;q.push(pii(0,str));
	while(!q.empty()){
		int u=q.top().se;q.pop();
		if(vis[u])continue;vis[u]=1; 
		for(pii &x:e[u]){
			if(dis[x.fi]>dis[u]+x.se){
				dis[x.fi]=dis[u]+x.se;
				q.push(pii(dis[x.fi],x.fi));
			}
		}
	}
}
inline int calc(int a,int b,int c,int d,int lx,int ly){
	chemn(ly,(b-a)/2),chemn(lx,(c-a)/2);
	return a+min(lx+ly,(d-a)/2);
}
inline int calc(edge x,edge y){
	int a=dis[x.u][y.u],b=dis[x.u][y.v],c=dis[x.v][y.u],d=dis[x.v][y.v],e=x.w,f=y.w;
	return max(max(calc(a,b+f,c+e,d+e+f,e,f),calc(b,a+f,d+e,c+e+f,e,f)),max(calc(c,d+f,a+e,b+e+f,e,f),calc(d,c+f,b+e,a+e+f,e,f)));
}
inline void solve(){
	n=read(),m=read(),ans=0;
	for(int i=1;i<=m;i++){
		int u=read(),v=read(),w=read()*2;
		E[i].u=u,E[i].v=v,E[i].w=w;
		chemx(ans,w/2);
		e[u].pb(pii(v,w)),e[v].pb(pii(u,w));
	}
	for(int i=1;i<=n;i++){
		memset(dis[i],127/3,sizeof(int)*(n+1));
		dijkstra(i,dis[i]);
	}
	for(int i=1;i<=m;i++)
	for(int j=i+1;j<=m;j++)
	chemx(ans,calc(E[i],E[j]));
	printf("%.1lf\n",1.0*ans/2);
	for(int i=1;i<=n;i++)
	memset(dis[i],0,sizeof(int)*(n+1)),e[i].clear();
}
int main(){
	int T=read();
	while(T--)solve();
}

T3:

凸包dpdp

考虑先枚举一个凸包的最左端点oo
其余点按照极角排序
f[i][j]f[i][j]表示当前凸包最后一个点为jj,上一个点为ii的方案数
考虑枚举ii转移
由于要满足凸包性质,所以可以按照ii的极角利用单调性O(n)O(n)转移
然后按对于ii极角从大到小对于每个jj判断一下是否有点在o,i,jo,i,j的三角形内即可

复杂度O(n3)O(n^3)

#include<bits/stdc++.h>
using namespace std;
#define cs const
#define re register
#define pb push_back
#define pii pair<int,int>
#define ll long long
#define fi first
#define se second
#define bg begin
cs int RLEN=1<<20|1;
inline char gc(){
    static char ibuf[RLEN],*ib,*ob;
    (ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
    return (ib==ob)?EOF:*ib++;
}
inline int read(){
    char ch=gc();
    int res=0;bool 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;
}
template<class tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
template<class tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
cs int mod=1e9+7;
inline int add(int a,int b){return (a+=b)>=mod?(a-mod):a;}
inline int dec(int a,int b){a-=b;return a+(a>>31&mod);}
inline int mul(int a,int b){static ll r;r=1ll*a*b;return (r>=mod)?(r%mod):r;}
inline void Add(int &a,int b){(a+=b)>=mod?(a-=mod):0;}
inline void Dec(int &a,int b){a-=b,a+=a>>31&mod;}
inline void Mul(int &a,int b){static ll r;r=1ll*a*b;a=(r>=mod)?(r%mod):r;}
inline int ksm(int a,int b,int res=1){for(;b;b>>=1,Mul(a,a))(b&1)&&(Mul(res,a),1);return res;}
inline int Inv(int x){return ksm(x,mod-2);}
inline int fix(int x){return (x<0)?x+mod:x;}
cs int N=505;
struct pt{
	int x,y;
	pt(int _x=0,int _y=0):x(_x),y(_y){}
	friend inline pt operator +(cs pt &a,cs pt &b){return pt(a.x+b.x,a.y+b.y);}
	friend inline pt operator -(cs pt &a,cs pt &b){return pt(a.x-b.x,a.y-b.y);}
	friend inline int operator *(cs pt &a,cs pt &b){return a.x*b.y-a.y*b.x;}
}p[N];
inline int cross(int a,int b,int c){
	return (p[a]-p[c])*(p[b]-p[c]);
}
int tp;
inline bool cmp(cs int &a,cs int &b){
	return cross(a,b,tp)>0;
}
inline bool comp(cs pt &a,cs pt &b){
	return a.x==b.x?a.y<b.y:a.x<b.x;
}
int f[N][N],id[N][N*2],ql[N],qr[N],tl,tr;
int n,ans;
int main(){
	#ifdef Stargazer
	freopen("lx.in","r",stdin);
	#endif
	n=read();
	for(int i=1;i<=n;i++)p[i].x=read(),p[i].y=read();
	sort(p+1,p+n+1,comp);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++)id[i][j]=j;
		id[i][i]=1;tp=i;
		sort(id[i]+2,id[i]+i+1,cmp);
		sort(id[i]+i+1,id[i]+n+1,cmp);
		for(int j=n+1;j<2*n;j++)id[i][j]=id[i][j-n+1];
	}
	for(int i=1;i<=n;i++){
		memset(f,0,sizeof(f));
		for(int j=i+1;j<=n;j++){
			int p=id[i][j],ps=0;
			tl=tr=0;
			for(int k=2;k<=n;k++)if(id[p][k]==i){ps=k;break;}
			for(int k=ps;k<ps+n;k++)if(id[p][k]>i){
				if(cross(id[p][k],i,p)>0)qr[++tr]=id[p][k];
				else ql[++tl]=id[p][k];
			}
			int s=0;
			for(int l=1,r=1;r<=tr;){
				if(l>tl||cross(ql[l],qr[r],p)>0)
				Add(f[p][qr[r]],s),r++;
				else Add(s,f[ql[l]][p]),l++;
			}
			int pre=0;
			while(tr){
				if(!pre||cross(qr[tr],pre,i)>0)
				Add(f[p][qr[tr]],1),pre=qr[tr];
				else f[p][qr[tr]]=0;
				tr--;
			}
			for(int k=j+1;k<=n;k++)Add(ans,f[p][id[i][k]]);
		}
	}
	cout<<ans<<'\n';
}

posted @ 2020-02-18 20:54  Stargazer_cykoi  阅读(201)  评论(0编辑  收藏  举报