TC SRM 638 DIV1 600 NarrowPassage2

Problem Statement

在一个狭长的通道中有$n$只狼,每只狼的体积为$size_i$,如果相邻的两只狼体积不超过$m$,则可以交换位置,求可以有多少种排列。

$n≤50,1≤m≤1,000,000,000$

Tutorial

每次选出区间中体积最大的狼,如果其他狼可以越过它,那么即可在整个区间里自由移动,而不能越过它的狼则被隔离到两个区间里,可以分治

区间总共有$n$只狼,能自由移动的狼个数为$cnt$,那么最后结果等于$$solve(l)*solve(r)*A_{n}^{cnt}$$

给定一些拓扑关系然后统计一些信息的题,算上这题最近遇到3道:
Permutation,结构是树,但因为要统计逆序对数比较烦,树形dp

局部极小值,因为是网格,而且标记的是局部极小值,所以可以通过确定较少的点状压dp计算结果

关于本题,我想到的部分

首先,可以在区间内畅通无阻的狼可以随便取一个位置

然后一个点如果两边的点都过不去,就可以分成2个子问题

因为“两边的点都过不去”这个条件并不清晰,所以我放弃了分治这个思路

正解利用了区间体积最大这个性质实现了分治

路曼曼其修远兮……

局部极小值和本题都有一个类似DAG的模型,所以我开始都试着往图论+dp的方向想==

现在我可以得到一个简洁的结论 DAG拓扑排序的结果有多少种可能 是NP问题

应该可以帮助以后少走一些弯路吧

还有关于拓扑问题的突破口其实也很简单:最值

然后就是挖性质、玩套路的本事了==

 1 #include <set>
 2 #include <ctime>
 3 #include <queue>
 4 #include <cstdio>
 5 #include <bitset>
 6 #include <cctype>
 7 #include <bitset>
 8 #include <cstdlib>
 9 #include <cassert>
10 #include <cstring>
11 #include <iostream>
12 #include <algorithm>
13 #define inf (1<<30)
14 #define INF (1ll<<62)
15 #define fi first
16 #define se second
17 #define rep(x,s,t) for(register int x=s,t_=t;x<t_;++x)
18 #define per(x,s,t) for(register int x=t-1,s_=s;x>=s_;--x)
19 #define travel(x) for(int I=last[x],to;I&&(to=e[I].to);I=e[I].nxt)
20 #define prt(x) cout<<#x<<":"<<x<<" "
21 #define prtn(x) cout<<#x<<":"<<x<<endl
22 #define pb(x) push_back(x)
23 #define hash asfmaljkg
24 #define rank asfjhgskjf
25 #define y1 asggnja
26 #define y2 slfvm
27 using namespace std;
28 typedef long long ll;
29 typedef pair<int,int> ii;
30 template<class T>void nt(T x){
31     if(!x)return;
32     nt(x/10);
33     putchar(x%10+‘0‘);
34 }
35 template<class T>void pt(T x){
36     if(x<0)putchar(‘-‘),x=-x;
37     if(!x)putchar(‘0‘);
38     else nt(x);
39 }
40 template<class T>void ptn(T x){
41     pt(x);putchar(‘\n‘);
42 }
43 template<class T>void pts(T x){
44     pt(x);putchar(‘ ‘);
45 }
46 template<class T>inline void Max(T &x,T y){if(x<y)x=y;}
47 template<class T>inline void Min(T &x,T y){if(x>y)x=y;}
48
49 const int maxn=55;
50 const int mod=1000000007;
51 class NarrowPassage2 {
52 public:
53     ll cnk[maxn][maxn],fac[maxn];
54     int m;
55     int solve(vector<int>d){
56         if(d.size()<=1)return 1;
57         int n=d.size();
58         int v=-1,id;
59         rep(i,0,n){
60             if(d[i]>v){
61                 v=d[i];
62                 id=i;
63             }
64         }
65         vector<int>l,r;
66         int cnt=0;
67         rep(i,0,id){
68             if(d[i]+v<=m)cnt++;
69             else l.pb(d[i]);
70         }
71         rep(i,id+1,n){
72             if(d[i]+v<=m)cnt++;
73             else r.pb(d[i]);
74         }
75         return (ll)solve(l)*solve(r)%mod*cnk[n][cnt]%mod*fac[cnt]%mod;
76     }
77     int count(vector<int>d, int maximum) {
78         cnk[0][0]=fac[0]=1;
79         rep(i,1,d.size()+1)
80             fac[i]=fac[i-1]*i%mod;
81         rep(i,0,d.size()+1){
82             rep(j,1,i)cnk[i][j]=(cnk[i-1][j-1]+cnk[i-1][j])%mod;
83             cnk[i][0]=cnk[i][i]=1;
84         }
85         m=maximum;
86         return solve(d);
87     }
88 };
时间: 2024-11-03 22:20:58

TC SRM 638 DIV1 600 NarrowPassage2的相关文章

[TC SRM 697 div1 lev1] DivisibleSetDiv1

Tutorial:https://apps.topcoder.com/wiki/display/tc/SRM+697#DivisibleSetDiv1 Note:证明过程值得一看. 主要内容:寻找[x1,x2,...,xn]使得满足bi * xi >= S - xi,其中S = x1 + x2 + ... + xn.

TC SRM 637 DIV1 500 PathGame

Problem Statement 给一个2*1000的board,每个格子黑或者白.白格子从左到右连成一条连接第一列和最后一列的path,path上相邻两格有公共边.两人轮流把白格子涂成黑格子,最后一个被迫涂黑格子使path断开的人输.问先手必胜还是必败. (Translated By myq_952) Tutorial 做sg的题有点生(有什么生不生的不就dp嘛) 考虑以一段2*k的全白矩形作为局面,涂黑一个格子会把原局面拆成两个后继局面,然后$n^2$求局面的sg即可 要注意的是,因为本题

[TC SRM 662 div1 lev1] FoxesOfTheRoundTable

转载:http://codeforces.com/blog/entry/19151 Note: 将问题转化为寻找hamiltonian回路问题.证明过程值得一看. Suppose the heights are sorted: h[0] <= h[1] <= h[2] ... In one hand, we know the answer can't be smaller than max{x[i+2] — x[i]}. We can proof this in the following w

TC SRM 655 DIV1 250,500pt

250: 给一个n*n的格子图,每个格子颜色为白色或者红色.假设刚开始都是白色,每次可以涂k*k的一块正方形格子区域,涂成红色或白色,后面涂的可以覆盖前面涂的.给你最终状态,问从初始状态涂任意次数,可不可以涂成最终状态. 挺不错的题,感觉比500有意思.刚开始想简单了,就从前往后枚举,碰到跟最终状态不同就涂.很显然错了.其实实质还是贪心,因为后涂的覆盖前面涂的,所以从最后开始考虑,每次选一块完整颜色相同的出来,涂成该颜色,然后以后该区域的颜色就不会变了,这样贪心的每次选一块可以涂的区域出来,直到

TC srm 673 300 div1

TC srm.673 300 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 Description 给你n(n<=50)匹马和n个人,一匹马和一个人能够组成一个骑兵,这个骑兵的战斗力等于马的战斗力乘以人的战斗力,问你有多少种组合方式满足其他骑兵的战斗力都不超过第0号骑兵. Input Output Sample Input Sample Output HINT 题意 题解: 大概就暴力枚举哪匹马和第0号人匹配,后面的骑兵我们按照战斗力从大到小排序之后,

Topcoder SRM 643 Div1 250&lt;peter_pan&gt;

Topcoder SRM 643 Div1 250 Problem 给一个整数N,再给一个vector<long long>v; N可以表示成若干个素数的乘积,N=p0*p1*p2*......*pn,我们假设p0,p1,...,pn是单调不降的,那么v里存储的是下标为偶数 的N的质因数p0,p2,p4,...,p(2k).现在要求写一个程序,返回一个vector<long long>ans; ans里存储的是p0,p1,p2,...,pn. Limits Time Limit(m

SRM 618 DIV1 500

非常棒的组合问题,看了好一会,无想法.... 有很多做法,我发现不考虑顺序的最好理解,也最好写. 结果一定是两种形式 A....A   dp[n-1] A...A...A sgma(dp[j]*dp[n-j-1])( 1<=j<=n-2) 最后乘上n! 什么时候才能自己在比赛中做出一个500分来啊!!! class LongWordsDiv1 { public : int count(int n) { int i,j; fact[0] = 1; for(i = 1; i <= n; i

SRM 631 DIV1

SRM 631 DIV1 A:最多肯定只需要两步,中间的两行,一行黑,一行白就可以了,这样的话,只需要考虑一开始就满足,和枚举一行去染色满足的情况就可以了,暴力即可 B:贪心,一个记录当前有猫的位置和当前超过一只猫的位置,然后位置排序从左往右找,如果当前能移动到之前超过两只的位置,就全部移动过去,不增加,如果不行,那么考虑当前这个能不能铺成一条,如果可以,相应更新位置,如果不行,就让猫全部堆到右边右边去,然后堆数多1 代码: A: #include <iostream> #include &l

SRM 622 div1 250

Problem Statement    In the Republic of Nlogonia there are N cities. For convenience, the cities are numbered 0 through N-1. For each two different cities i and j, there is a direct one-way road from i to j. You are given the lengths of those roads a