zoukankan      html  css  js  c++  java
  • Topcoder 15405

    题面传送门

    题意:
    给出两个长度为 (n) 的数组 (a,b) 和一个整数 (s)
    你可以任意重排数组 (a,b),总共 ((n!)^2) 种方案。
    现在又两个人 A,B 来玩游戏,两人轮流操作,A 先操作。
    每次操作当前选手会取出各自数组的第一个元素 (x) 并将它删去,并令 (s) 减去 (x),如果发现 (sleq 0),那么当前操作的人输,游戏结束。
    求在所有 ((n!)^2) 的方案中,有多少种能够使得 A 赢,答案模 (10^9+7)
    (1 leq n,a_i,b_i leq 100)(1 leq s leq sum(a_i+b_i)),时限 (=4s)

    我竟然现场 40min 就 A 了这道题,incredible!
    拿总方案数 (-) B 赢的方案数。
    考虑 B 赢是什么情况。肯定我们删到了某个位置 (i),然后删除完第 (i) 个位置上的数之后 (s leq 0),然后 A 就输了。
    假设 A 在第 (i) 次删除的数为 (x)。那么在删除 (x) 之前,删除的所有数之和 (<s),而删完 (x) 之后删除的所有数之和 (geq s)
    我们枚举这个 (i)(x),假设删 (a_i) 之前删除的所有数之和为 (sum),那么我们可以得到不等式 (s-x leq sum lt s)
    那么题目转化为:你在 (a_j) 中选择 (i-1) 个数填在 (a_1,a_2,dots,a_{i-1}) 的位置(已经放好的 (x) 就不能再被选择了),再从 (b_j) 中选择 (i-1) 个数放在 (b_1,b_2,dots,b_{i-1}) 的位置,满足 (a,b) 数组中选出来的 (2(i-1)) 个数之和在 ([s-x,s)) 之间,求方案数。
    首先 (n^3) 的暴力 (dp) 是很显然的。你每枚举一个 (x),就相当于从 (a) 数组中踢掉了一个数,就重新做一遍背包,(dpa_{i,j,k}) 表示在 (a_1,a_2,dots,a_i) 中选择 (j) 个数和为 (k) 的方案数。(dpb) 同理。然后枚举 (sum) 和选出来的 (i-1)(a_i) 的和,用乘法原理计算贡献。(a_1,a_2,dots,a_{i-1}) 可以随便排,方案数 ((i-1)!)(b_1,b_2,dots,b_{i-1}) 也可以随便排,方案数也是 ((i-1)!)(a_{i+1},a_{i+2},dots,a_{n})(b_i,b_{i+1},dots,b_n) 也依次有一个全排列的系数,所以总的乘法系数是 (((i-1)!)^2 imes(n-i)! imes(n-i+1)!)。总复杂度 (n^5)

    不过借鉴 [CTSC2012] 假面 的经验,可以先预处理出整个序列的 (dpa),然后对每个 (x) 都跑一遍可删除背包。正推的方程式是 (dp_{i,j,k}=dp_{i-1,j,k}+dp_{i-1,j-1,k-x})。现在是在已知 (dp_{i}) 的情况下求出 (dp_{i-1})。注意到 (dp_{i-1,0,k}=dp_{i,0,k}),所以我们可以先还原出 (dp_{i-1,0,k}),再根据 (dp_{i-1,1,k}=dp_{i,1,k}-dp_{i-1,0,k-x}) 还原出 (dp_{i-1,1,k}),以此类推,还原的复杂度是 (n^2) 的。
    接下来是计算答案,还是枚举 (a) 贡献的和 (suma),不过注意到 (sum) 的取值范围是一段区间,所有 (b) 贡献的和的范围也是个区间 ([s-x-suma,s-suma)),前缀和转移,又可以优化掉一个 (n)

    时间复杂度 (mathcal O(n^4))

    #include <bits/stdc++.h>
    using namespace std;
    #define fi first
    #define se second
    #define fz(i,a,b) for(int i=a;i<=b;i++)
    #define fd(i,a,b) for(int i=a;i>=b;i--)
    #define ffe(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
    #define fill0(a) memset(a,0,sizeof(a))
    #define fill1(a) memset(a,-1,sizeof(a))
    #define fillbig(a) memset(a,63,sizeof(a))
    #define pb push_back
    #define ppb pop_back
    #define mp make_pair
    typedef long long ll;
    typedef pair<int,int> pii;
    const int MOD=1e9+7;
    const int MAXN=100+5;
    const int MAXS=2e4+5;
    int n,s,a[MAXN],b[MAXN];
    int dpa[MAXN][MAXS],dpb[MAXN][MAXS],sdp[MAXN][MAXS];
    int ndp[MAXN][MAXS];
    int fac[MAXN];
    int solve(){
    	int sa=0,sb=0,ss=0;
    	fac[0]=1;for(int i=1;i<=n;i++) fac[i]=1ll*fac[i-1]*i%MOD;
    	for(int i=1;i<=n;i++) sa+=a[i];
    	for(int i=1;i<=n;i++) sb+=b[i];
    	ss=sa+sb;dpa[0][0]=1;
    	for(int i=1;i<=n;i++) for(int j=i;~j;j--) for(int k=sa;~k;k--)
    		if(j>=1&&k>=a[i]) dpa[j][k]=(dpa[j][k]+dpa[j-1][k-a[i]])%MOD;
    	dpb[0][0]=1;
    	for(int i=1;i<=n;i++) for(int j=i;~j;j--) for(int k=sb;~k;k--)
    		if(j>=1&&k>=b[i]) dpb[j][k]=(dpb[j][k]+dpb[j-1][k-b[i]])%MOD;
    	for(int i=0;i<=n;i++){
    		sdp[i][0]=dpb[i][0];
    		for(int j=1;j<=ss;j++) sdp[i][j]=(sdp[i][j-1]+dpb[i][j])%MOD;
    	}
    	int ans=0;
    	for(int i=1;i<=n;i++){
    		for(int j=0;j<=n;j++) for(int k=0;k<=sa;k++) ndp[j][k]=dpa[j][k];
    		for(int j=0;j<n;j++) for(int k=0;k<=sa-a[i];k++){
    			ndp[j+1][k+a[i]]=(ndp[j+1][k+a[i]]-ndp[j][k]+MOD)%MOD;
    		}
    		int l=max(s-a[i],0),r=s-1;
    		for(int j=0;j<n;j++){
    			int sum=0;
    			for(int k=0;k<=sa;k++){
    				if(k>r) break;
    				int nl=l-k,nr=r-k;
    				sum=(sum+1ll*ndp[j][k]*sdp[j][nr]%MOD)%MOD;
    				if(nl>0) sum=(sum-1ll*ndp[j][k]*sdp[j][nl-1]%MOD+MOD)%MOD;
    			}
    			ans=(ans+1ll*sum*fac[j]%MOD*fac[j]%MOD*fac[n-j-1]%MOD*fac[n-j]%MOD)%MOD;
    		}
    	}
    	int tot=1ll*fac[n]*fac[n]%MOD;
    	return (tot-ans+MOD)%MOD;
    }
    class PrettyLiar{
    public:
    	int count(int S,vector<int> kaede,vector<int> kanade){
    		s=S;n=kaede.size();
    		for(int i=0;i<n;i++) a[i+1]=kaede[i],b[i+1]=kanade[i];
    		return solve();
    	}
    };
    //PrettyLiar pro;
    
  • 相关阅读:
    实验四 (1):定义一个形状类(Shape)方法:计算周长,计算面积
    计算机结构的简化模型
    memcached性能测试之Twemperf
    Eclipse UML小工具AmaterasUML的配置和使用
    Kafka中文官方文档
    HBase Snapshot简介
    shell脚本学习系列之一---入门
    linux中shell变量$#,$@,$0,$1,$2的含义解释
    vim常用操作
    Linux多台主机间配置SSH免密登陆
  • 原文地址:https://www.cnblogs.com/ET2006/p/Topcoder-15405.html
Copyright © 2011-2022 走看看