HZNU Training 2 for Zhejiang Provincial Competition 2020

A - Largest Submatrix of All 1’s

 POJ - 3494

题意:给一个只包含0和1的n*m的矩形,求由‘1’围成的最大矩形的面积。

分析:单调栈的应用,对n行每一行处理,可转化为POJ - 2559求最大矩形的面积。注意点:如果加入的元素破坏了非单调递减,清栈之后要把栈顶元素值更新为新加入的元素。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int maxn = 2005;
 6 typedef long long ll;
 7 int nums[maxn][maxn];
 8 int st[maxn];
 9 int main(){
10     int n,m;
11     while (~scanf("%d%d",&n,&m)){
12         memset(nums,0,sizeof nums);
13         for (int i = 1; i <= n; i++){
14             for (int j = 1; j <= m; j++){
15                 scanf("%d",&nums[i][j]);
16             }
17         }
18         for (int i = 1; i <= n; i++){
19             for (int j = 1; j <= m; j++){
20                     if (nums[i][j]) nums[i][j] += nums[i-1][j];
21             }
22         }
23         ll s = 0;
24         for (int i = 1; i <= n; i++){
25             int top = 0; 
26             memset(st,0,sizeof st);
27             nums[i][m+1] = -1;
28             for (int j = 1; j <= m+1; j++){
29                 if (top == 0 || nums[i][j] >= nums[i][st[top-1]]) {
30                     st[top++] = j;
31                 }
32                 else{
33                     int pos; 
34                     while (top && nums[i][st[top-1]] > nums[i][j]){
35                         pos = st[top-1];
36                         s = max(s,(ll)(j-st[top-1])*(ll)nums[i][st[top-1]]);
37                         top--;
38                     }
39                     st[top++] = pos;
40                     nums[i][pos] = nums[i][j];//关键点                
41                 }
42             }
43         }
44         printf("%lld
",s);
45     }
46     return 0;
47 }
View Code

B - Ayoub's function

 CodeForces - 1301C 

题意:给一个长度为n的01串,含有m个1,求如何组合能使含1子区间数最多,输出最多数量。

分析:总含1子区间数 = 总子区间数 - 总连续0子区间数,要使答案最大,总连续0子区间数要最少。最优方案(不作证明)是把所有0均分区间,注意:剩下的0不能全部给一个区间,也要均分到每个区间。此外当m>=n/2时最优解一定为0和1交替分配,剩下的1随意分配,可以直接计算得答案减少一半的枚举次数。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 int main(){
 5     int T;
 6     ll n, m;
 7     scanf("%d", &T);
 8     while (T--) {
 9         scanf("%lld%lld",&n,&m);
10         if (m==0) puts("0");
11         else if (m>=(n/2)){
12             printf("%lld
",m+(n-1)*n/2);
13         }
14         else{
15             ll nums = (n-m)/(m+1),l = (n-m)%(m+1);
16             printf("%lld
",n*(n+1)/2-l*(nums+1)*(nums+2)/2+(m+1-l)*nums*(nums+1)/2);
17         }
18     }
19     return 0;
20 }
View Code

C - Managing Difficulties

 Gym - 102411M

题意:求数组中任意三个数构成等差数列的组数。

分析:枚举起点、中点、终点之中任意2个,理论上通过这两个点可以推得第三个数,只需查询并统计所有第三个数的数量。给的时间2s,组数 t <= 10,n <= 2000,枚举两个点需要O(n^2)的复杂度,单看n时间是足够的,但数组中的数可以达到1e9,有些方案使用map可以卡着时间过,但注意到n只有2000,十分明显可以离散化处理优化时间复杂度,离散化后对该题给的数据时间可以降低3倍以上,但使用离散化对枚举的点有特殊要求,具体看代码实现。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn = 2005;
 4 typedef long long ll;
 5 int ans,m,n,t;
 6 ll arr[maxn],a[maxn],b[maxn];
 7 int mp[maxn];
 8 inline ll read() {
 9     char ch = getchar(); ll x = 0, f = 1;
10     while(ch < '0' || ch > '9') {
11         if(ch == '-') f = -1;
12         ch = getchar();
13     } while('0' <= ch && ch <= '9') {
14         x = x * 10 + ch - '0';
15         ch = getchar();
16     } return x * f;
17 }
18 int get(ll x){
19     int pos = lower_bound(b+1,b+1+m,x)-b;
20     if (b[pos]!=x) pos = 0;
21     return pos; 
22 }
23 int main(){
24     scanf("%d",&t);
25     while (t--){
26         ans = 0,m = 0;
27         scanf("%d",&n);
28         for (int i = 1; i <= n; i++){
29             a[i] = b[i] =  read();
30         }
31         sort(b+1,b+1+n);
32         m = unique(b+1,b+1+n)-b-1;
33         for (int i = 1; i <= n ;i++)
34         arr[i] = lower_bound(b+1,b+1+m,a[i])-b,mp[arr[i]]++;
35         
36         for (int i = 1; i <= n; i++){
37             mp[arr[i]]--;
38             for (int j = i+1; j <= n; j++){
39                 mp[arr[j]]--;
40                 ll tmp = 2*a[j]-a[i];
41                 if (tmp>=1&&tmp<=b[m]) ans += mp[get(tmp)];
42             }
43             for (int j = i+1; j <= n; j++) mp[arr[j]]++;
44         }
45         for (int i = 0; i <= m; i++) mp[i] = 0;
46         printf("%d
",ans);
47     }
48     return 0;
49 }
View Code

F - Binary String Minimizing

 CodeForces - 1256D

题意: 给一个长度为n的01串,能够把相邻的两个数交换k次,输出交换完后最小字典序的01串。

分析:把0尽可能往前放,可以从字符串第一个位置开始枚举,只要移动次数够就把0移到那个位置,不够就往前移剩余移动次数次。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 int main(){
 5     string str;
 6     ll q,k,n;
 7     cin>>q;
 8     while (q--){
 9         cin>>n>>k>>str;
10         ll cnt = 0;
11         for (ll i = 0; i < n; i++){
12             if (str[i] == '0'){
13                 if (i-cnt <= k) k -= i-cnt,swap(str[i],str[cnt++]);
14                 else swap(str[i],str[i-k]),k = 0;
15             }
16             if (!k) break;
17         }
18         cout<<str<<endl;
19     }
20     return 0;
21 }
View Code

H - A Simple Math Problem

 HDU - 5974

题意:给a,b,找满足条件x+y = a,lcm(x,y)= b的x、y,找不到输出No Solution。

分析:lcm(x,y) = x * y / gcd(x,y)  = b 易证 gcd(a,b) = gcd(x,y),2个未知数2个方程可以直接把x和y算出来,如果不是整数输出No Solution即可。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 inline ll gcd(ll a, ll b) {
 5     return b == 0 ? a : gcd(b, a%b);
 6 }
 7 int main(){
 8     ll a,b,X,Y;
 9     while (~scanf("%lld %lld",&a,&b)){
10         double y = (a-sqrt(a*a-4*b*gcd(a,b)))/2;
11         if (y == (ll)y) {
12             Y = y;
13             if (Y <= a-Y)
14             printf("%lld %lld
",Y,a-Y);
15             else
16             printf("%lld %lld
",a-Y,Y);
17         }
18         else printf("No Solution
");
19     }
20     return 0;
21 }
View Code
原文地址:https://www.cnblogs.com/hznudreamer/p/12424139.html