LOJ500 ZQC的拼图 二分答案、DP

传送门

题意:给出$N$个直角三角形拼图和$M imes M$的网格,第$i$个直角三角形水平直角边边长为$frac{1}{a_i}$,垂直直角边边长为$frac{1}{b_i},$规定直角三角形只能直角顶点在右上方地摆放,直角顶点必须摆放在网格的顶点处,且水平直角边和垂直直角边必须与网格的某一条线重合,三角形可以越出网格。现在你可以将每个三角形都放大正整数$K$倍,求存在一种摆放方案使得存在一条只经过直角三角形覆盖区域的$(0,0)$到$(M,M)$的路径的$K$的最小值。$N , M leq 100 , a_i , b_i leq 10^6$


显然是有二分性质的

首先考虑到交换两个直角三角形对答案实际上没有影响,所以拼图的顺序是无所谓的。

所以我们选择DP作为二分的check。设$f_{i,j}$表示前$i$个拼图在横坐标为$j$时最大的纵坐标大小,转移方程用枚举当前三角形直角顶点的位置加上相似推一下就行。

 1 #include<bits/stdc++.h>
 2 #define LOJ
 3 //This code is written by Itst
 4 #define ll long long
 5 using namespace std;
 6 
 7 inline int read(){
 8     int a = 0;
 9     bool f = 0;
10     char c = getchar();
11     while(c != EOF && !isdigit(c)){
12         if(c == '-')
13             f = 1;
14         c = getchar();
15     }
16     while(c != EOF && isdigit(c)){
17         a = (a << 3) + (a << 1) + (c ^ '0');
18         c = getchar();
19     }
20     return f ? -a : a;
21 }
22 
23 ll tri[101][2] , dp[101] , N , M;
24 
25 bool check(int mid){
26     memset(dp , -0x3f , sizeof(dp));
27     dp[0] = 0;
28     for(int i = 1 ; i <= N ; i++)
29         for(int j = M ; j >= 0 ; j--)
30             for(int k = j ; k >= 0 && (j - k) * tri[i][0] <= mid ; k--)
31                 dp[j] = max(dp[j] , dp[k] + (mid - (j - k) * tri[i][0]) / tri[i][1]);
32     return dp[M] >= M;
33 }
34 
35 int main(){
36 #ifdef LOJ
37     freopen("500.in" , "r" , stdin);
38     //freopen("500.out" , "w" , stdout);
39 #endif
40     N = read();
41     M = read();
42     for(int i = 1 ; i <= N ; i++){
43         tri[i][0] = read();
44         tri[i][1] = read();
45     }
46     int L = 1 , R = 1e8;
47     while(L < R){
48         int mid = L + R >> 1;
49         check(mid) ? R = mid : L = mid + 1;
50     }
51     cout << L;
52     return 0;
53 }
原文地址:https://www.cnblogs.com/Itst/p/9879680.html