2023.08.12 codeforces round 892 div2

发布时间 2023-08-14 19:34:42作者: 不如讨饭

年轻人的第三场div2(已完成:ABCDE

rank:1265

solved:4

rating change:+276

new rating:1323

A.United We Stand

题意:给定一个数列a,问是否能分成两个非空的数列b和c,使得c中任意一个数不是b中任意一个数的因子;

若x是y的因子则有x<=y;因此不妨将数列的最大值放入c,把剩下的数放入b;注意数列中的数值全相同时无解;

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 ll read(){
 5     char ch=getchar();ll x=0,f=1;
 6     while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
 7     while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
 8     return x*f;
 9 }
10 const int maxn=105; 
11 ll T,N,lb,lc;
12 ll A[maxn];
13 int main(){
14     T=read();
15     while(T--){
16         N=read();
17         int flag=false;
18         for(int i=1;i<=N;i++){
19             A[i]=read();
20             if(A[i]!=A[1])flag=true;
21         }
22         if(flag==false){
23             cout<<"-1"<<endl;
24         }
25         else{
26             sort(A+1,A+N+1);
27             int t=0;
28             for(int i=N;i>=1;i--){
29                 if(A[i]==A[N])t++;
30             }
31             cout<<N-t<<" "<<t<<endl;
32             for(int i=1;i<=N-t;i++){
33                 cout<<A[i]<<" ";
34             } 
35             cout<<endl;
36             for(int i=N-t+1;i<=N;i++){
37                 cout<<A[i]<<" ";
38             }
39             cout<<endl;
40         }
41     }
42     return 0;
43 }

 

B.Olya and Game with Arrays

题意:给定N个数列,每个数列至少有两个数,可以将其中的最多一个数移动到别的数列(可以不移动),问每一列数的最小值的和的最大值是多少;

显然,所有数中最小的数一定要选;对于一个数列,由于我们最多只能移走一个数,因此,每一列数的最小值小于等于其次小值,每一列数最小值的和和 < 所有次小值的和;我们记录每一列数的最小值和次小值,我们不妨将所有的最小值移动的次小值最小的数列中去,即可令和=较大的N-1个次小值+所有数中最小的数;

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 int read(){
 5     char ch=getchar();int x=0,f=1;
 6     while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
 7     while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
 8     return x*f;
 9 }
10 const int maxn=5e4+5;
11 const int maxm=1e9+7;
12 int T,N,M,tot;
13 int A[maxn],B[maxn][5];
14 int main(){
15     T=read();
16     while(T--){
17         N=read();
18         tot=0;
19         ll ans=0,mi1=maxm,mi2=maxm,cnt1=0,cnt2=0;
20         for(int i=1;i<=N;i++){
21             M=read();
22             for(int j=1;j<=M;j++){
23                 A[j]=read();
24             }
25             sort(A+1,A+M+1);
26             B[i][0]=A[1];B[i][1]=A[2];    
27             if(B[i][0]<mi1){
28                 mi1=B[i][0];cnt1=i;
29             }
30             if(B[i][1]<mi2){
31                 mi2=B[i][1];cnt2=i;
32             }
33         }
34         for(int i=1;i<=N;i++){
35             if(i!=cnt2)ans+=B[i][1];
36             if(i==cnt1)ans+=B[i][0];
37         }
38         cout<<ans<<endl;
39     }
40     return 0;
41 }

 

C.Another Permutation Problems

题意:给定长度N,求对于N的所有排列对于该式子的最大值:

看了样例N=2和N=4的情况是将N和N-1换位置,其他数字按照原顺序,然后写了,然后样例后面几个数没过;于是推了一下5,发现5的最大值在排列为12543时取到,然后大胆猜想最大值是把最后的长度为x的区间翻转(比较对称(?))得到的,于是枚举长度x,写了,过了,但是没有证明;

 

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 int read(){
 5     char ch=getchar();int x=0,f=1;
 6     while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
 7     while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
 8     return x*f;
 9 }
10 const int maxn=255;
11 int T,N;
12 int A[maxn];
13 int main(){
14     T=read();
15     while(T--){
16         N=read();
17         ll ans=0;
18         for(int i=1;i<=N-1;i++)ans+=i*i;
19         for(int i=1;i<=N;i++){
20             ll ma=0,sum1=0,sum2=0,t=0;
21             
22             for(int j=1;j<i;j++)sum1+=j*j;
23             
24             for(int j=i;j<=N;j++){
25                 t++;
26                 sum2+=j*(N-t+1);
27                 ma=max(ma,j*(N-t+1)); 
28             }
29             ans=max(ans,sum1+sum2-ma);
30         }
31         cout<<ans<<endl;
32     }
33     return 0;
34 }

放一下正解(等有空了一定回来看()):

作者代码:

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <set>
 4 #include <stack>
 5 #include <vector>
 6 using namespace std;
 7 void solve() {
 8     int N = 0; cin >> N;
 9     int ans = 0;
10     vector<int> pr;
11     pr.assign(N * N, -1);
12     for (int i = 1; i <= N; ++i) {
13         for (int j = 1; j <= N; ++j) {
14             pr[i * j - 1] = 1;
15         }
16     }
17     for (int mx = N * N; mx >= 1; --mx) {
18         if (pr[mx - 1] == -1) continue;
19         vector<vector<int>> a;
20         int curans = -mx;
21         bool br = false;
22         a.assign(N, vector<int>());
23         for (int j = N; j >= 1; --j) {
24             int num = min(mx / j, N);
25             if (num < 1) {
26                 br = true;
27                 break;
28             }
29             a[num - 1].push_back(j);
30         }
31         if (br) break;
32         stack<int> s;
33         for (int i = 0; i < N; ++i) {
34             s.push(i + 1);
35             bool brk = false;
36             for (auto x : a[i]) {
37                 if (s.empty()) {
38                     brk = true; break;
39                 }
40                 curans += s.top() * x;
41                 s.pop();
42             }
43             if (brk) break;
44         }
45         ans = max(ans, curans);
46     }
47     cout << ans << "\n";
48 }
49  
50 int main() {
51     ios_base::sync_with_stdio(false);
52     cin.tie(nullptr);
53     int t = 0; cin >> t;
54     while (t--) solve();
55     return 0;
56 }

D.Andrey and Escape from Capygrad

题意:跑路,有很多传送门,对于给定的一个传送门,有四个相关的参数l,r,a,b,有l<=a<=b<=r;如果一个人的位置x有l<=x<=r,那么传送门可以把他传送到任意y(a<=y<=b)现在给定Q个询问,每个询问给定一个人初始位置,问能到达的最远位置;

显然对于给定的四个参数l,r,a,b,只有l,b是对答案有影响的,其实原式等价于当一个人的位置为x(l<=x<=b)时最远可以到达b,因为如果位置大于b时最远只能在原位;

对于给定的传送门,我们先进行排序操作,然后对于有重叠部分的我们直接合并成一个新的传送门,对于询问的起始点x二分查找(佬用的upper_bound)第一个l<=x的传送门,并比较x和该传送门能到达的最远位置;

题解用的离线查询+扫描线;

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int read(){
 4     char ch=getchar();int x=0,f=1;
 5     while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
 6     while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
 7     return x*f;
 8 }
 9 const int maxn=2e5+5;
10 int T,N,Q,tot;
11 struct node{
12     int l,r,a,b;
13 }e[maxn];
14 struct no{
15     int l,r;
16 }t[maxn];
17 int cmp(node x,node y){
18     if(x.l==y.l)return x.b<y.b;
19     return x.l<y.l;
20 }
21 int check(int mid,int x){
22     if(x>=t[mid].l)return 1;
23     return 0;
24 }
25 int main(){
26     T=read();
27     while(T--){
28         N=read();
29         for(int i=1;i<=N;i++){
30             e[i].l=read();e[i].r=read();e[i].a=read();e[i].b=read();
31         }
32         sort(e+1,e+N+1,cmp);
33         tot=1;t[tot].l=e[1].l,t[tot].r=e[1].b;
34         for(int i=1;i<=N;i++){
35             if(e[i].l<=t[tot].r){
36                 t[tot].r=max(t[tot].r,e[i].b);
37                 continue;
38             }
39             else{
40                 tot++;t[tot].l=e[i].l;t[tot].r=e[i].b;
41             }
42         }
43         Q=read();
44         for(int i=1;i<=Q;i++){
45             int x=read();
46             int L=1,R=tot,ans=0;
47             while(L<=R){
48                 int mid=(L+R)>>1;
49                 if(check(mid,x))ans=mid,L=mid+1;
50                 else R=mid-1;
51             }
52             cout<<max(t[ans].r,x)<<" ";
53         }
54         cout<<endl;
55         for(int i=1;i<=N;i++){
56             e[i].l=e[i].r=e[i].a=e[i].b=0;
57             t[i].l=t[i].r=0;
58         }
59     }
60     return 0;
61 }

E.Maximum Mogonosity

题意:给定两个长度为 N 的数列 A 和 B,定义区间 [ l , r ] 的 cost 为 f ( l , r ) = abs ( Al - Br ) + abs ( Ar - Bl ) ;求总长度为 K 的不相交的区间的 cost 的和的最大值;

定义 dp [ n1 ] [ k1 ] 为区间总长度为k1,所有不相交的区间都有 r < n1 的 cost 的和的最大值;

可以得到状态转移方程:dp [ n1 ] [ k1 ] = max ( dp [ n1-1 ] [ k1 ] , dp [ n1-l  ] [ k-l ] + f ( n1-l+1 , n1 ) );

由绝对值的性质可以得到 abs ( a - b ) + abs ( c - d ) = max ( a - b + c - d , a - b - c + d , - a + b + c - d , - a + b - c + d ) ;

优化:用 mx  数组维护前面的区间的最大值,详情见代码注释:

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 ll read(){
 5     char ch=getchar();ll x=0,f=1;
 6     while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
 7     while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
 8     return x*f;
 9 }
10 const int maxn=3e3+5; 
11 ll T,N,K;
12 ll A[maxn],B[maxn],dp[maxn][maxn],f[maxn][maxn];
13 ll mx1[maxn],mx2[maxn],mx3[maxn],mx4[maxn];
14 int main(){
15     T=read();
16     while(T--){
17         N=read();K=read();
18         for(int i=1;i<=N;i++)A[i]=read();
19         for(int i=1;i<=N;i++)B[i]=read();
20         
21         for(int i=0;i<=N;i++){
22             mx1[i]=B[i+1]-A[i+1];
23             mx2[i]=B[i+1]+A[i+1];
24             mx3[i]=-B[i+1]-A[i+1];
25             mx4[i]=-B[i+1]+A[i+1];
26         }//以i+1作为下一个区间的l 
27         //mx数组表示:当前的dp值+下一个区间的fl的最大值; 
28         
29 //dp[n1][k1]=max(dp[n1-1][k1],dp[n1-l][k1-l]+fl(n1-l+1)+fr(n1));fl(x)与fr(x)分别表示以x作为区间的l和r时的值; 
30 //mx[n1-k1]=max(dp[n1-l][k1-l]+fl(n1-l+1));
31         
32         for(ll i=1;i<=N;i++){//n1;
33             for(ll j=1;j<=min(i,K);j++){//k1; 
34                 dp[i][j]=dp[i-1][j];
35                 dp[i][j]=max(dp[i][j],mx1[i-j]+B[i]-A[i]);
36                 dp[i][j]=max(dp[i][j],mx2[i-j]-B[i]-A[i]);
37                 dp[i][j]=max(dp[i][j],mx3[i-j]+B[i]+A[i]);
38                 dp[i][j]=max(dp[i][j],mx4[i-j]-B[i]+A[i]);
39                 //dp值取四种情况的最大值; 
40                 //max(dp[n1-1][k1],mx[n1-k1]+fr[n1]);
41                 if(i<N){
42                     mx1[i-j]=max(mx1[i-j],dp[i][j]+B[i+1]-A[i+1]);
43                     mx2[i-j]=max(mx2[i-j],dp[i][j]+B[i+1]+A[i+1]);
44                     mx3[i-j]=max(mx3[i-j],dp[i][j]-B[i+1]-A[i+1]);
45                     mx4[i-j]=max(mx4[i-j],dp[i][j]-B[i+1]+A[i+1]);
46                 }//维护dp的两个维度的差值一定时的最大值; 
47             }
48         }
49         cout<<dp[N][K]<<endl;
50     }
51     return 0;
52 }