2019.07.05【NOIP提高组】模拟 A 组

47 篇文章 0 订阅
13 篇文章 0 订阅

JZOJ 3301 家族

题目

在一个图中,割掉某些边,使其成为若干个连通块,相应的连通块的个数影响权值,问在使权值和不少于 k k k的情况下,让选择的边的极差最小


分析

按边权从小到大排序,选择一段区间,求出权值和,用并查集维护,时间复杂度 O ( m 2 α ( m ) ) O(m^2\alpha(m)) O(m2α(m))


代码

#include <cstdio>
#include <cctype>
#include <algorithm>
#define rr register
using namespace std;
const int N=1301;
struct node{
	int x,y,w;
	bool operator <(const node &t)const{
		return w<t.w;
	}
}e[N<<2];
int f[N],a[N],siz[N],n,m,lim;
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline signed getf(int u){return f[u]==u?u:f[u]=getf(f[u]);}
signed main(){
	n=iut(); m=iut(); lim=iut();
	for (rr int i=1;i<=n;++i) a[i]=iut();
	for (rr int i=1;i<=m;++i) e[i]=(node){iut(),iut(),iut()};
	sort(e+1,e+1+m); rr int ans=2147483647;
	for (rr int i=1;i<=m;++i){
		rr int sum=n*a[1];
		for (rr int j=1;j<=n;++j) f[j]=j,siz[j]=1;
		for (rr int k=i;k<=m;++k){
			if (e[k].w-e[i].w>=ans) break; 
			rr int fa=getf(e[k].x),fb=getf(e[k].y);
			if (fa>fb) fa^=fb,fb^=fa,fa^=fb;
			if (fa==fb) continue;
			sum+=a[siz[fa]+siz[fb]]-a[siz[fa]]-a[siz[fb]];
			f[fa]=fb,siz[fb]+=siz[fa];
			if (sum>=lim){
				ans=e[k].w-e[i].w;
				break;
			}
		}
	}
	if (ans==2147483647) printf("T_T"); else printf("%d",ans);
	return 0;
} 

JZOJ 3302 供电网络

题目


分析

首先是一个显然的最小费用最大流,还有上下界,那就用EK吧,每次只流1的流量,不断动态加边,对于输送到别的城市的费用,每次流过1的流量后就再加一条边 a x 2 + b x − a ( x − 1 ) 2 − b ( x − 1 ) = a x 2 + b x − a x 2 + 2 a x − a − b x + b = 2 a ( x − 1 ) + b ax^2+bx-a(x-1)^2-b(x-1)=ax^2+bx-ax^2+2ax-a-bx+b=2a(x-1)+b ax2+bxa(x1)2b(x1)=ax2+bxax2+2axabx+b=2a(x1)+b


代码

#include <cstdio>
#include <cctype>
#include <cstring>
#include <deque>
#define rr register
using namespace std;
const int inf=200000;
struct node{int y,w,f,next;}e[80001]; bool v[211];
int ls[211],dis[211],rest[211],k=1,ans,m,n,s,t,w[211][211],x[611],y[611],l[611],u[611],a[611],b[611],pre[211];
inline signed iut(){
	rr int ans=0,f=1; rr char c=getchar();
	while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans*f;
}
inline void add(int x,int y,int w,int f){
	e[++k]=(node){y,w,f,ls[x]} ,ls[x]=k,
	e[++k]=(node){x,0,-f,ls[y]},ls[y]=k;
}
inline bool spfa(){
	for (rr int i=1;i<=m;++i)
	if (w[x[i]][y[i]]==l[i]&&l[i]<u[i])
	    ++l[i],add(x[i],y[i],1,a[i]*(l[i]*2-1)+b[i]);
	memset(dis,42,sizeof(dis)); dis[s]=0,v[s]=1;
	rr deque<int>q; q.push_front(s);
	while (q.size()){
		rr int x=q.front(); q.pop_front();
		for (rr int i=ls[x];i;i=e[i].next)
		if (e[i].w&&dis[e[i].y]>dis[x]+e[i].f){
			dis[e[i].y]=dis[x]+e[i].f,pre[e[i].y]=i;
			if (!v[e[i].y]){
				v[e[i].y]=1;
				if (q.size()&&dis[e[i].y]<dis[q.front()]) q.push_front(e[i].y);
				    q.push_back(e[i].y);
			}
		}
		v[x]=0;
	}
	if (dis[t]<=0) ans+=dis[t];
	return dis[t]<=0;
}
inline void update(){
	rr int now=t;
	while (now!=s){
		rr int x=e[pre[now]^1].y,y=e[pre[now]].y;
		--e[pre[now]].w,++e[pre[now]^1].w;
		++w[x][y],--w[y][x],now=x;
	}
}
signed main(){
	n=iut(),m=iut(),s=n+1,t=s+1;
	for (rr int i=1;i<=n;++i)
		rest[i]=iut(),add(s,i,inf,iut()),add(i,t,inf,iut());
	for (rr int i=1;i<=m;++i){
		x[i]=iut(),y[i]=iut(),a[i]=iut(),b[i]=iut(),l[i]=iut(),u[i]=iut();
		rest[x[i]]-=l[i],rest[y[i]]+=l[i];
		ans+=a[i]*l[i]*l[i]+b[i]*l[i],w[x[i]][y[i]]+=l[i],w[y[i]][x[i]]-=l[i];
	}
	for (rr int i=1;i<=n;++i){
		if (rest[i]>0) add(s,i,rest[i],-inf);
		    else add(i,t,-rest[i],-inf);
	}
	while (spfa()) update();
	ans%=inf,ans=ans<0?ans+inf:ans;
	return !printf("%d",ans);
}

JZOJ 3303 洛谷 4841 城市规划

POJ 1737加强版
洛谷题目链接
弱化版博客


分析

根据弱化版, f [ n ] = 2 n ( n − 1 ) / 2 − ∑ i = 1 n − 1 f [ i ] C n − 1 i − 1 2 ( n − i ) ( n − i − 1 ) / 2 \large f[n]=2^{n(n-1)/2}-\sum_{i=1}^{n-1}f[i]C_{n-1}^{i-1}2^{(n-i)(n-i-1)/2} f[n]=2n(n1)/2i=1n1f[i]Cn1i12(ni)(ni1)/2
把这个式子拆开可以得到
f [ n ] = 2 n ( n − 1 ) / 2 − ( n − 1 ) ! ∑ i = 1 n − 1 f [ i ] ( i − 1 ) ! 2 ( n − i ) ( n − i − 1 ) / 2 ( n − i ) ! \large f[n]=2^{n(n-1)/2}-(n-1)!\sum_{i=1}^{n-1}\frac{f[i]}{(i-1)!}\frac{2^{(n-i)(n-i-1)/2}}{(n-i)!} f[n]=2n(n1)/2(n1)!i=1n1(i1)!f[i](ni)!2(ni)(ni1)/2
同除 ( n − 1 ) ! (n-1)! (n1)!并移项可以得到
f [ n ] ( n − 1 ) ! = 2 n ( n − 1 ) / 2 ( n − 1 ) ! − ∑ i = 1 n − 1 f [ i ] ( i − 1 ) ! 2 ( n − i ) ( n − i − 1 ) / 2 ( n − i ) ! \large \frac{f[n]}{(n-1)!}=\frac{2^{n(n-1)/2}}{(n-1)!}-\sum_{i=1}^{n-1}\frac{f[i]}{(i-1)!}\frac{2^{(n-i)(n-i-1)/2}}{(n-i)!} (n1)!f[n]=(n1)!2n(n1)/2i=1n1(i1)!f[i](ni)!2(ni)(ni1)/2
∵ 2 ( n − n ) ( n − n − 1 ) / 2 ( n − n ) ! = 1 \because\frac{2^{(n-n)(n-n-1)/2}}{(n-n)!}=1 (nn)!2(nn)(nn1)/2=1
∴ 2 n ( n − 1 ) / 2 ( n − 1 ) ! = ∑ i = 1 n f [ i ] ( i − 1 ) ! 2 ( n − i ) ( n − i − 1 ) / 2 ( n − i ) ! \large\therefore\frac{2^{n(n-1)/2}}{(n-1)!}=\sum_{i=1}^n\frac{f[i]}{(i-1)!}\frac{2^{(n-i)(n-i-1)/2}}{(n-i)!} (n1)!2n(n1)/2=i=1n(i1)!f[i](ni)!2(ni)(ni1)/2
这就是一个卷积的模式,可以转换成 H ( n ) = F ( n ) G ( n ) H(n)=F(n)G(n) H(n)=F(n)G(n)
那么 F ( n ) = G ( n ) − 1 H ( n ) F(n)=G(n)^{-1}H(n) F(n)=G(n)1H(n),用NTT解决
多项式求逆怎么办,懒得证明了我太菜了,时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)


代码

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define rr register
using namespace std;
const int N=131072,mod=1004535809,inv3=334845270;
int f[N<<2],g[N<<2],r[N<<2],jc[N],inv[N],n;
inline signed iut(){
    rr int ans=0; rr char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    return ans;
}
inline signed ksm(int x,int y){
    rr int ans=1;
    for (;y;y>>=1,x=1ll*x*x%mod)
        if (y&1) ans=1ll*ans*x%mod;
    return ans;
}
inline signed mo1(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline signed mo2(int x,int y){return x<y?x-y+mod:x-y;}
inline void ntt(int *f,int n,int op){
    for (rr int i=0;i<n;++i)
    if (i<r[i]) swap(f[i],f[r[i]]);
    for (rr int p=2;p<=n;p<<=1){
        rr int len=p>>1,w=ksm(~op?3:inv3,(mod-1)/p);
        for (rr int i=0;i<n;i+=p)
            for (rr int j=i,t=1;j<i+len;++j,t=1ll*t*w%mod){
                rr int z=1ll*f[len+j]*t%mod;
                f[len+j]=mo2(f[j],z),f[j]=mo1(f[j],z);
            }
    }
}
int g1[N<<2];
inline void tnt(int *f,int *t,int len1,int len2,int tot){
    rr int n=1; for (;n<len1+len2;n<<=1);
    for (rr int i=len2;i<n;++i) g1[i]=0;
    for (rr int i=0;i<len2;++i) g1[i]=t[i];
    rr int inv=ksm(n,mod-2);
    for (rr int i=0;i<n;++i) r[i]=(r[i>>1]>>1)|((i&1)?n>>1:0);
    ntt(f,n,1),ntt(g1,n,1);
    for (rr int i=0;i<n;++i) f[i]=1ll*f[i]*g1[i]%mod;
    ntt(f,n,-1); for (rr int i=0;i<tot;++i) f[i]=1ll*f[i]*inv%mod;
    for (rr int i=tot;i<n;++i) f[i]=0; 
}
int r1[N<<2],r2[N<<2];
inline void invm(int *f,int m){
    rr int n=1; for (;n<m;n<<=1);
    r2[0]=ksm(f[0],mod-2);
    for (rr int p=2;p<=n;p<<=1){
        for (rr int i=0;i<p;++i) r1[i]=mo1(r2[i],r2[i]);
        tnt(r2,r2,p>>1,p>>1,p),tnt(r2,f,p,p,p);
        for (rr int i=0;i<p;++i) r2[i]=mo2(r1[i],r2[i]); 
    }
    for (rr int i=0;i<m;++i) f[i]=r2[i];
}
signed main(){
    n=iut()+1;
    inv[0]=inv[1]=jc[0]=jc[1]=f[0]=1;
    for (rr int i=2;i<n;++i) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
    for (rr int i=2;i<n;++i) inv[i]=1ll*inv[i-1]*inv[i]%mod,jc[i]=mo1(jc[i-1],jc[i-1]);
    for (rr int i=3;i<n;++i) jc[i]=1ll*jc[i-1]*jc[i]%mod;
    for (rr int i=1;i<n;++i) f[i]=1ll*jc[i]*inv[i]%mod,g[i]=1ll*jc[i]*inv[i-1]%mod;
    invm(f,n); rr int m=1; for (;m<=(n<<1);m<<=1); tnt(f,g,m,m,m);
    return !printf("%lld",1ll*f[n-1]*ksm(inv[n-2],mod-2)%mod);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值