zoukankan      html  css  js  c++  java
  • 清华集训2016Day4

    清华集训2016Day4

    组合数问题(problem)

    用卢卡斯定理可知满足条件即将(n)(m)分别用(k)进制表示,要求(n)的每一位都要大于等于(m)的对应位。直接数位(dp),设(f_{i,0/1,0/1})表示处理到第(i)位,(n)是否触上界,(m)是否触上界时的方案数。复杂度(O(tlog_kn))

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    #define ll long long
    const ll mod = 1000000007;
    int t,k,l,a[100],b[100];ll n,m,f[100][4];
    int main(){
    	freopen("problem.in","r",stdin);
    	freopen("problem.out","w",stdout);
    	scanf("%d%d",&t,&k);
    	while (t--){
    		scanf("%lld%lld",&n,&m);m=min(n,m);
    		int all=((2*n-m+2)%mod)*((m+1)%mod)%mod*500000004%mod;
    		memset(a,0,sizeof(a));memset(b,0,sizeof(b));
    		l=0;while (m) b[++l]=m%k,m/=k;
    		l=0;while (n) a[++l]=n%k,n/=k;
    		f[0][0]=f[0][1]=f[0][2]=f[0][3]=1;
    		for (int i=1;i<=l;++i){
    			f[i][0]=(k*(k+1)>>1)*f[i-1][0]%mod;
    			f[i][1]=((a[i]*(a[i]+1)>>1)*f[i-1][0]+(a[i]+1)*f[i-1][1])%mod;
    			f[i][2]=((b[i]*(2*k-b[i]+1)>>1)*f[i-1][0]+(k-b[i])*f[i-1][2])%mod;
    			if (b[i]<=a[i])
    				f[i][3]=(f[i-1][3]+(a[i]-b[i])*f[i-1][2]+b[i]*f[i-1][1]+(b[i]*(2*a[i]-b[i]+1)>>1)*f[i-1][0])%mod;
    			else
    				f[i][3]=((a[i]+1)*f[i-1][1]+(a[i]*(a[i]+1)>>1)*f[i-1][0])%mod;
    		}
    		printf("%lld
    ",(all-f[l][3]+mod)%mod);
    	}
    	return 0;
    }
    

    汽水(soda)

    看见平均值自然可以想到分数规划。题目中所给的(k)可以减到每条边的权值里面去,这样问题就变成了找一条路径使其平均值的绝对值最小。

    先点分,对于每个分治重心做一次二分。假设组成答案路径的是((A,B),(C,D))这两个二元组,其中(A,C)代表两条到根路径的权值和,(B,D)代表长度。二分(-k<frac{A+C}{B+D}<k),只需要判断是否存在满足条件的二元组即可。

    先假设(A+Cge0),那么就只需要满足(frac{A+C}{B+D}<k)这个条件,即(kB-A>C-kD)。按(A)从小到大枚举((A,B)(Age0)),加入所有使(A+Cge0)((C,D)),维护(C-kD)的最小值即可。考虑到((A,B),(C,D))不能来自于分治重心的同一棵子树,故需要维护来自不同子树的最小及次小值。

    (A+C<0)同理,可得(A+kB>-C-kD),故维护(-C-kD)的最小值即可。

    这样复杂度为(O(nlog^2n))

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    #define ll long long
    #define pi pair<ll,int>
    #define mk make_pair
    const int N = 50005;
    int n,to[N<<1],nxt[N<<1],head[N],cnt,sz[N],w[N],vis[N],root,sum,top,pos;
    ll ww[N<<1],ans=1ll<<60;
    struct data{
    	ll x,y,z;
    	data(){x=y=z=0;}
    	data(ll _x,ll _y,ll _z){x=_x,y=_y,z=_z;}
    	bool operator < (const data &b) const {return y<b.y;}
    }s[N];
    pi m1,m2;
    void getroot(int u,int f){
    	sz[u]=1;w[u]=0;
    	for (int e=head[u];e;e=nxt[e])
    		if (to[e]!=f&&!vis[to[e]]){
    			getroot(to[e],u),sz[u]+=sz[to[e]];
    			w[u]=max(w[u],sz[to[e]]);
    		}
    	w[u]=max(w[u],sum-sz[u]);
    	if (w[u]<w[root]) root=u;
    }
    void dfs(int u,int f,ll dep,ll dis,int ac){
    	s[++top]=data(dep,dis,ac);
    	for (int e=head[u];e;e=nxt[e])
    		if (to[e]!=f&&!vis[to[e]])
    			dfs(to[e],u,dep+1,dis+ww[e],ac);
    }
    void upt(pi S){
    	if (S.first<m1.first){
    		if (S.second!=m1.second) m2=m1;
    		m1=S;
    	}else if (S.first<m2.first&&S.second!=m1.second) m2=S;
    }
    bool chk1(ll k){
    	m1=m2=mk(1ll<<60,0);
    	for (int i=pos,j=pos-1;i<=top;++i){
    		while (j&&s[i].y+s[j].y>=0) upt(mk(s[j].y-k*s[j].x,s[j].z)),--j;
    		if (k*s[i].x-s[i].y>(s[i].z==m1.second?m2.first:m1.first)) return true;
    		upt(mk(s[i].y-k*s[i].x,s[i].z));
    	}
    	return false;
    }
    bool chk2(ll k){
    	m1=m2=mk(1ll<<60,0);
    	for (int i=pos-1,j=pos;i;--i){
    		while (j<=top&&s[i].y+s[j].y<0) upt(mk(-k*s[j].x-s[j].y,s[j].z)),++j;
    		if (k*s[i].x+s[i].y>(s[i].z==m1.second?m2.first:m1.first)) return true;
    		upt(mk(-k*s[i].x-s[i].y,s[i].z));
    	}
    	return false;
    }
    void solve(int u){
    	vis[u]=1;s[top=1]=data(0,0,0);
    	for (int e=head[u];e;e=nxt[e])
    		if (!vis[to[e]]) dfs(to[e],u,1,ww[e],to[e]);
    	sort(s+1,s+top+1);
    	for (pos=1;s[pos].y<0;++pos) ;
    	ll l=1,r=ans;
    	while (l<=r){
    		ll mid=l+r>>1;
    		if (chk1(mid)||chk2(mid)) ans=r=mid-1;
    		else l=mid+1;
    	}
    	for (int e=head[u];e;e=nxt[e])
    		if (!vis[to[e]]){
    			root=0,sum=sz[to[e]];
    			getroot(to[e],u),solve(root);
    		}
    }
    int main(){
    	freopen("soda.in","r",stdin);
    	freopen("soda.out","w",stdout);
    	ll k;scanf("%d%lld",&n,&k);
    	for (int i=1;i<n;++i){
    		int u,v;ll w;scanf("%d%d%lld",&u,&v,&w);w-=k;ans=min(ans,abs(w));
    		to[++cnt]=v;nxt[cnt]=head[u];ww[cnt]=w;head[u]=cnt;
    		to[++cnt]=u;nxt[cnt]=head[v];ww[cnt]=w;head[v]=cnt;
    	}
    	sum=w[0]=n;getroot(1,0);solve(1);
    	printf("%lld
    ",ans);return 0;
    }
    

    定向越野(circle)

    咕咕咕

  • 相关阅读:
    在智能手机上跟踪ADS-B系统的飞机航线信息
    用C#将XML转换成JSON
    在DB2中使用EXPORT实现将数据导出文本文件
    使用Powerdesigner生成设计的数据表(一张或多张)的测试数据
    PowerDesigner常用设置
    转载自——Json.Net如何在序列化之前修改属性值
    转载自——Json.net动态序列化以及对时间格式的处理
    Newtonsoft.Json序列化和反序列
    DB2 数据库中字段特定字符替换为空
    常用公共DNS服务器地址
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/10050816.html
Copyright © 2011-2022 走看看