A:http://codeforces.com/contest/1398/problem/A
题意:
在非递减序列中找非法三角形
解析:
刚开始搞了个结构体排序,然后才发现给出的就是非递减。。。
看1,2,n,如果它三能组成三角形,一定不存在非法。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=5e4+20; ll a[maxn]; struct node { int x; int id; }st[maxn]; bool cmp(node a,node b) { return a.x<b.x; } int main() { int t; cin>>t; while(t--) { int n; cin>>n; for(int i=1;i<=n;i++) { cin>>a[i]; } int x1=a[1],x2=a[2],x3=a[n]; if((x1+x2)>x3&&(x3-x1)<x2&&(x3-x2)<x1&&(x2-x1)<x3) cout<<"-1"<<endl; else cout<<"1 2 "<<n<<endl; } }
B:http://codeforces.com/contest/1398/problem/B
题意:
01字符串。
操作是每次删除一串连续1,得分为连续1的数目。两人依次操作,求先手的得分。
解析:
把所有连续1收集起来,排序,从大到小拿即可。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=5e4+20; int a[maxn]; int b[maxn]; struct node { int x; int id; }st[maxn]; bool cmp(node a,node b) { return a.x<b.x; } int main() { int t; cin>>t; while(t--) { string s; cin>>s; int le=s.length(); int cnt=0,ok=0,tot=0; for(int i=0;i<le;i++) { if(s[i]=='1') { int md=1,k; int ok2=0; if(i<le-1){ for(int j=i+1;j<le;j++) { if(s[j]=='1') md++; else { k=j; ok2=1; break; } } } if(!ok) { // cnt+=md; ok=1; } else ok=0; b[tot++]=md; if(!ok2) { break; } i=k-1; } } ok=0; cnt=0; sort(b,b+tot); for(int i=tot-1;i>=0;i--) { if(!ok) { cnt+=b[i];ok=1; } else ok=0; } cout<<cnt<<endl; } }
C:http://codeforces.com/contest/1398/problem/C
题意:
求所有好序列的数目。
好序列:sum[j]-sum[i]==j-i+1
解析:
很明显,先把前缀和弄出来。
有:sumj-sum(i-1)==j-i+1
考虑把所有数字均-1,那么变成:sumj-sum(i-1)-(j-i+1)=0
那么就是求:所有区间和为0的区间数。
n*n很明显行不通。
如果某个sum出现多次,那么这一次与上一次的区间和就为0,与上上一次的区间和也为0,那么总的可构造的数目就是:cnt+=sum之前出现的数目
map记录次数,记得初始化mp[0]==0。
#include<bits/stdc++.h> #include<map> #include<iostream> #include<cstring> #include<cmath> using namespace std; typedef long long ll; const int maxn=1e5+20; const ll inf=0x3f3f3f3f3f3f3f3f; int main() { int t; cin>>t; while(t--) { int n; cin>>n; map<ll,int>m; string s; cin>>s; m[0]++; ll sum=0; ll cnt=0; for(int i=0;i<s.length();i++) { sum+=s[i]-'1'; //-1 cnt+=m[sum]; m[sum]++; } cout<<cnt<<endl; } }
D:http://codeforces.com/contest/1398/problem/D
题意:
给定若干个红色,绿色,蓝色的一对长度一样的棍子.问用这些棍子组成的颜色不同的矩形的面积的最大总和是多少.注意不能把两个相同颜色的一对棍子拆成两个分别去用.其次颜色不同指的是在两个集合里选的两对棍子.
解析:
考虑贪心,但是写着很麻烦。。
就看了题解,原来是个三维DP
定义dp[i][j][k],表示红色用了i个,绿色用了j个,蓝色用了k个的前提下,所获得的最大矩形面积和。
理解这个转移方程,还是之前的dp思路:选的大还是不选的大?
#include<bits/stdc++.h> #include<map> #include<iostream> #include<cstring> #include<cmath> using namespace std; typedef long long ll; const int maxn=2e2+20; //const ll inf=0x3f3f3f3f3f3f3f3f; int r[maxn],g[maxn],b[maxn]; ll dp[maxn][maxn][maxn]; int main() { int c1,c2,c3; cin>>c1>>c2>>c3; for(int i=1;i<=c1;i++) cin>>r[i];sort(r+1,r+1+c1); for(int i=1;i<=c2;i++) cin>>g[i];sort(g+1,g+1+c2); for(int i=1;i<=c3;i++) cin>>b[i];sort(b+1,b+1+c3); ll maxx=0; for(int i=0;i<=c1;i++) { for(int j=0;j<=c2;j++) { for(int k=0;k<=c3;k++) { if(i&&j) dp[i][j][k]=max(dp[i][j][k],dp[i-1][j-1][k]+r[i]*g[j]); if(i&&k) dp[i][j][k]=max(dp[i][j][k],dp[i-1][j][k-1]+r[i]*b[k]); if(j&&k) dp[i][j][k]=max(dp[i][j][k],dp[i][j-1][k-1]+g[j]*b[k]); maxx=max(maxx,dp[i][j][k]); } } } cout<<maxx<<endl; }