\(Codeforces-Round 767\) (Div. 2) F2. \(Game \ on \ Sum\)

\(HERE\)

题意

\(QZS\) 和 \(HANGRY\) 玩游戏。

游戏共有 \(n\) 轮, 对于整一局游戏给定一个 \(K\) , 游戏的过程是在改变一个数 \(a\) 的值 , 初始为 \(1\) .

在每一轮中 \(QZS\) 会在 \([1 , k]\) 的区间里取出一个 \(\bf{实数}\) , \(HANGRY\) 选择用 \(a\) 加上这个实数还是减去这个实数 , \(HANGRY\) 的目的是让 \(a\) 最小 , \(QZS\) 相反.

在这 \(n\) 轮中 , \(HANGRY\) 至少选择 \(m\) 轮选择加 .

\(HANGRY\) 和 \(QZS\) 都是绝顶聪明的 , 这意味着他们会选择最优解 .

问最后的 \(a\) 是多少 . 多测.答案对 \(1e9+7\) 取模.

数据范围:

$n \le 10^6 , m \le n , T \le 5 \times 10^5 \sum n = 10^6 $

\(\sum n\) 为每个测试点所有测试数据中 \(n\) 的和.

题解

\(O(nm)\) (<100 pts)

考虑 \(DP\)

\(dp_{i,j}\) 表示长度为 \(i\) , 选了 \(j\) 个减。

则方程为:

\[dp_{i , j} = \frac{dp_{i - 1 , j} + dp_{i - 1 , j - 1}}{2}
\]

显然

code

114514
#include <bits/stdc++.h>
#define int long long
using namespace std ;
const int N = 2e3 + 10 ;
const int mod = 1e9 + 7 ; int dp[N][N] , n , T , m , K ;
int nueyong ; inline int read() {
int x = 0 , f = 1 ;
char c = getchar() ; while ( c < '0' || c > '9' ) { if ( c == '-' ) f = -f ; c = getchar() ;
} while ( c >= '0' && c <= '9' ) {
x = x * 10 + c - '0' ;
c = getchar() ;
} return x * f ;
} inline int Regular_Quick_Pow( int a , int b ) {
int ans = 1 ; while ( b > 0 ) { if ( b & 1 ) ans = ( ans * a ) % mod ; b >>= 1 ; a = ( a * a ) % mod ;
} return ans ;
} signed main() { #ifndef ONLINE_JUDGE
freopen( "1.in" , "r" , stdin ) ;
freopen( "1.out" , "w" , stdout ) ;
#endif T = read() ; nueyong = Regular_Quick_Pow( 2 , mod - 2 ) ; while ( T -- ) { n = read() , m = read() , K = read() ;
dp[1][0] = K , dp[1][1] = 0 ; for ( int i = 2 ; i <= n ; ++ i ) { dp[i][0] = ( i * K ) % mod ; for( int j = 1 ; j <= min(i - 1 , n - m) ; ++ j ) { dp[i][j] = ( ( ( dp[i - 1][j - 1] + dp[i - 1][j] ) % mod ) * nueyong ) % mod ; } } cout << dp[n][n - m] << '\n' ;
}
}

组合方法

我们目前把这个东西写出来

    1     0     0     0     0     0     0     0     0     0     0
4 1 0 0 0 0 0 0 0 0 0
12 5 1 0 0 0 0 0 0 0 0
32 17 6 1 0 0 0 0 0 0 0
80 49 23 7 1 0 0 0 0 0 0
192 129 72 30 8 1 0 0 0 0 0
448 321 201 102 38 9 1 0 0 0 0
1024 769 522 303 140 47 10 1 0 0 0
2304 1793 1291 825 443 187 57 11 1 0 0
5120 4097 3084 2116 1268 630 244 68 12 1 0

对于点 \(i , j\) 来说, 答案是 \(\frac{dp_{i , j}}{2^{i - 1}} \times K\)

我们考虑点 \((i , j)\) , 使他用第 \(0\) 列表示出来,我们摆出来一个杨辉三角,来看看:

  1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1

我们能够发现,将 \(i , j\) 看做 \(0 , 0\) 他下面的选的次数可以用杨辉三角的某个点表示。

并且为(点设为 \((n , n - m)\) , 与上面我们的dp做法衔接一下 ):

\[ans = \sum_{i = 1}^{n - 1}C^{n - m - 1}_{n - i - 1} \times dp_{i , 0}\times K
\]

注意两个 -1 , 关于这个位置为啥要减一,这里解释一下:

对于当已经到 \(0\) 时,在杨辉三角中的位置依然可能有上一位转过来,但是两行的首位是没有关系的,那么他只能够由他的左上方的点转移过来,就相当于左上方的值了。

code

114514
#include <bits/stdc++.h>
#define int long long
using namespace std ;
const int N = 2e6 + 10 ;
const int mod = 1e9 + 7 ; int n , T , m , K ;
int now[N] ; inline int read() {
int x = 0 , f = 1 ;
char c = getchar() ; while ( c < '0' || c > '9' ) { if ( c == '-' ) f = -f ; c = getchar() ;
} while ( c >= '0' && c <= '9' ) {
x = x * 10 + c - '0' ;
c = getchar() ;
} return x * f ;
} namespace Combination {
int D[N] ; int nueyong[N] , sum_neo[N] , sum[N] ; inline void lear_neoyong() { sum_neo[0] = sum_neo[1] = 1 ;
nueyong[1] = 1 ; nueyong[0] = 1 ;
sum[0] = sum[1] = 1 ; for( int i = 2 ; i < N ; ++ i ) { int p = mod ;
int k = p / i ;
nueyong[i] = ( k * ( p - nueyong[p % i] ) ) % p ;
sum_neo[i] = ( nueyong[i] * sum_neo[i - 1] ) % p ;
sum[i] = ( i * sum[i - 1] ) % p ; }
} int Quick_Pow( int alpha , int beta )
{
int ans = 1 ; while ( beta > 0 ) { if( beta & 1 ) ans = ( ans * alpha ) % mod ; beta >>= 1 ; alpha = ( alpha * alpha ) % mod ;
} return ans ;
} int Regular_C_of_Pow_Class( int n , int m ) {
int alpha = 1 , beta = 1 , rereturn = 0 ; if( m <= n && n >= 0 && m >= 0 ) { for( int i = n - m + 1 ; i <= n ; ++ i ) {
alpha = ( alpha * i ) % mod ; }
for( int i = 1 ; i <= m ; ++ i ) {
beta = ( beta * i ) % mod ;
} rereturn = ( alpha * Quick_Pow( beta , mod - 2 ) ) % mod ;
return rereturn ; } else return 0 ; } inline int jc( int x ) {
return sum[x] ;
} inline int neo_jc( int x ) { if ( x == 0 ) return 1 ; return sum_neo[x] ;
} int Regular_C_of_Inv( int n , int m ) {
return ( ( ( jc( n ) * neo_jc( n - m ) ) % mod ) * neo_jc( m ) ) % mod ;
} int C_Lucas_Using_Inv( int n , int m ) { if ( m > n ) return 0 ; if ( m == 0 ) return 1 ; return ( Regular_C_of_Inv( n % mod , m % mod ) * C_Lucas_Using_Inv( n / mod , m / mod ) ) % mod ;
} int C_Lucas_Using_Pow( int n , int m ) { if( m == 0 ) return 1 ; return ( Regular_C_of_Pow_Class( n % mod , m % mod ) * C_Lucas_Using_Pow( n / mod , m / mod ) ) % mod ;
} void Asking_for_Derangement() { D[0] = 1 ;
D[1] = 0 ;
D[2] = 1 ;
for( int i = 3 ; i < N ; ++ i ) { D[i] = ( i - 1 ) * ( D[i - 1] + D[i - 2] ) % mod ; }
} inline void Cleared() {
memset( D , 0 , sizeof(D) ) ;
memset( sum_neo , 0 , sizeof(sum_neo) ) ;
memset( sum , 0 , sizeof(sum) ) ;
memset( nueyong , 0 , sizeof(nueyong) ) ;
}
} ;
using namespace Combination ; inline int Regular_Quick_Pow( int a , int b ) {
int ans = 1 ; while ( b > 0 ) { if ( b & 1 ) ans = ( ans * a ) % mod ; b >>= 1 ; a = ( a * a ) % mod ;
} return ans ;
} signed main() { #ifndef ONLINE_JUDGE
freopen( "1.in" , "r" , stdin ) ;
freopen( "1.out" , "w" , stdout ) ;
#endif T = read() ;
lear_neoyong() ;
for ( int i = 1 ; i <= 1e6 * 2 ; ++ i ) {
now[i] = ( i * Regular_Quick_Pow( 2 , i - 1 ) ) % mod ;
} while ( T -- ) { n = read() , m = read() , K = read() ; if ( n - m == 0 ) {
cout << ( n * K ) % mod << '\n' ;
continue ;
} int ans = 0 ;
for ( int i = 1 ; i <= n - 1 ; ++ i ) { ans = ( ans + C_Lucas_Using_Inv( n - i - 1 , n - m - 1 ) * now[i] ) % mod ;
} cout << ( ( ( K * ans ) % mod ) * Regular_Quick_Pow( Regular_Quick_Pow( 2 , n - 1 ) , mod - 2 ) ) % mod << '\n' ;
}
}

结尾撒花 \(\color{pink}{✿✿ヽ(°▽°)ノ✿}\)

Game on Sum--组合数学--DP的更多相关文章

  1. 【uoj#22】[UR #1]外星人 组合数学+dp

    题目描述 给你一个长度为 $n$ 的序列 $\{a_i\}$ 和一个数 $x$ ,对于任意一个 $1\sim n$ 的排列 $\{p_i\}$ ,从 $1$ 到 $n$ 依次执行 $x=x\ \tex ...

  2. 【bzoj1925】[Sdoi2010]地精部落 组合数学+dp

    题目描述 传说很久以前,大地上居住着一种神秘的生物:地精. 地精喜欢住在连绵不绝的山脉中.具体地说,一座长度为 N 的山脉 H可分 为从左到右的 N 段,每段有一个独一无二的高度 Hi,其中Hi是1到 ...

  3. UVA 10891 Game of Sum(DP)

    This is a two player game. Initially there are n integer numbers in an array and players A and B get ...

  4. HDU 1003 Max Sum --- 经典DP

    HDU 1003    相关链接   HDU 1231题解 题目大意:给定序列个数n及n个数,求该序列的最大连续子序列的和,要求输出最大连续子序列的和以及子序列的首位位置 解题思路:经典DP,可以定义 ...

  5. UVALive 7143 Room Assignment(组合数学+DP)(2014 Asia Shanghai Regional Contest)

    题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&category=6 ...

  6. HDU-4532 湫秋系列故事——安排座位 组合数学DP

    题意:有来自n个专业的学生,每个专业分别有ai个同学,现在要将这些学生排成一行,使得相邻的两个学生来自不同的专业,问有多少种不同的安排方案. 分析:首先将所有专业的学生视作一样的,最后再乘以各自学生的 ...

  7. hdu 1003 Max sum(简单DP)

    Max Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Problem ...

  8. UVA - 10891 Game of Sum 区间DP

    题目连接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=19461 Game of sum Description This ...

  9. Codeforces Codeforces Round #319 (Div. 2) B. Modulo Sum 背包dp

    B. Modulo Sum Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/577/problem/ ...

  10. POJ 2479-Maximum sum(线性dp)

    Maximum sum Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 33918   Accepted: 10504 Des ...

随机推荐

  1. do{}while0的两个作用

    1.作为一种防止宏错误展开的一种防御性写法. 相信很多人都知道,这里不展开了. 2.实现 goto 语句的功能,一次break就可以跳出到后续语句. do { if(...) break; ... } ...

  2. Profinet IO从站数据 转EtherCAT项目案例

    目录 1 案例说明 1 2 VFBOX网关工作原理 1 3 准备工作 2 4 使用PRONETA软件获取PROFINET IO从站的配置信息 2 5 设置网关采集PROFINETIO从站设备数据 5 ...

  3. Java使用不同方式优雅拆分业务逻辑

    如何处理复杂的业务逻辑 在实际的业务开发当中,经常会遇到复杂的业务逻辑,可能实现出来的代码并没有什么问题,但是代码的可读性很差. 那么在实际开发中如何避免大面积的 if-else 代码块的问题? 补充 ...

  4. 使用过 Vue SSR 吗?说说 SSR?

    先说下基本概念: ssr 的全称是 server side render,服务端渲染,vue ssr 的意思就是在服务端进行 vue 的渲染,直接对前端返回带有数据,并且是渲染好的HTML页面: 而不 ...

  5. 解决方案 | vb记住上次打开的文件夹

      Private Sub Button_ImportBasicData_Click(sender As Object, e As EventArgs) Handles Button_ImportBa ...

  6. 网易传媒基于 Arctic 的低成本准实时计算实践

    网易传媒大数据实际业务中,存在着大量的准实时计算需求场景,业务方对于数据的实效性要求一般是分钟级:这种场景下,用传统的离线数仓方案不能满足用户在实效性方面的要求,而使用全链路的实时计算方案又会带来较高 ...

  7. SQL Thinking

    s2下半年我在内部有一次部门级别的技术分享会,以本文内容分享为主. 其实有很多人问过我相同的问题,遇到需要改写的慢sql,不知道怎么改,改好了以后也不知道等不等价?不等价了也不知道错在哪?这个要怎么破 ...

  8. Swift开发基础03-函数

    定义 形参默认是let,也只能是let func sum(v1: Int, v2: Int) -> Int { return v1 + v2 } sum(v1: 10, v2: 20) // 无 ...

  9. 在ubuntu16.04下,源码编译安装特定版本的MongoDB PHP扩展

    背景:我的php项目在连接其他mongo库时报:Server at xxx:27017 reports wire version 5, but this version of libmongoc re ...

  10. Python爬虫(1-4)-基本概念、六个读取方法、下载(源代码、图片、视频 )、user-agent反爬

    Python爬虫 一.爬虫相关概念介绍 1.什么是互联网爬虫 如果我们把互联网比作一张大的蜘蛛网,那一台计算机上的数据便是蜘蛛网上的一个猎物,而爬虫程序就是一只小蜘蛛,沿着蜘蛛网抓取自己想要的数据 解 ...