A - Bad Triangle
选出三个序列使之不能组成三角形。先把差距最大的选了,枚举中间值。两边之和不大于第三边。
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include<iostream>
#include<algorithm>
using namespace std;
const int N=50010;
int a[N];
int main()
{IO;int T;cin>>T;while(T--){int n;cin>>n;for(int i=1;i<=n;i++) cin>>a[i];int i;for(i=2;i<n;i++) if(a[1]+a[i]<=a[n])break;if(i==n) cout<<-1<<endl;else cout<<1<<' '<<i<<' '<<n<<endl;}return 0;
}
B - Substring Removal Game
第一次没加#include<vector>
还Compilation error
了。。
考虑原串中连续的1。两人一定轮流选择目前连续1个数最多的。把连续的1个数存到一个数组,逆序。两人轮流取即可。
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include<string>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=110;
int a[N];
int main()
{IO;int T;cin>>T;while(T--){string s;cin>>s;int n=s.size();vector<int> ans(n);for(int i=1;i<=n;i++) a[i]=s[i-1]-'0';for(int i=1;i<=n;i++){int j=i;while(j<=n&&a[i]==a[j]) j++;if(a[i]==1) ans.push_back(j-i);i=j-1;}int res=0;sort(ans.begin(),ans.end());reverse(ans.begin(),ans.end());for(int i=0;i<ans.size();i++) if(i%2==0) res+=ans[i];cout<<res<<endl;}return 0;
}
C - Good Subarrays
对于原数组a[l+1]+a[l+2]+⋯+a[r]=r−l+1a[l+1]+a[l+2]+\dots+a[r]=r-l+1a[l+1]+a[l+2]+⋯+a[r]=r−l+1考虑前缀和数组即a[r]−a[l]=r−la[r]-a[l]=r-la[r]−a[l]=r−l变换一下a[r]−r=a[l]−la[r]-r=a[l]-la[r]−r=a[l]−l。因此只需统计a[i]−ia[i]-ia[i]−i的个数,根据组合数的计算公式即可。由于可能有负数弄了个map
映射。上述情况未考虑i=0
的情况,因此最后应加上a[i]==i
的个数。
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include<cstdio>
#include<string>
#include<map>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=100010;
int a[N];
map<int,int> mp;
int idx=0;
int get(int s)
{if(!mp.count(s)) mp[s]=++idx;return mp[s];
}
ll cnt[N];
int main()
{IO;int T;cin>>T;while(T--){int n;cin>>n;mp.clear();for(int i=0;i<=n;i++) cnt[i]=0;idx=0;string s;cin>>s;for(int i=1;i<=n;i++) a[i]=s[i-1]-'0';for(int i=1;i<=n;i++) a[i]+=a[i-1];for(int i=1;i<=n;i++) cnt[get(a[i]-i)]++;ll res=0;for(int i=1;i<=idx;i++) res+=1ll*cnt[i]*(cnt[i]-1)/2;for(int i=1;i<=n;i++)if(a[i]==i) res++;cout<<res<<endl;}return 0;
}
这题很快就想到怎么写了,但是码代码能力还是不行写了半天。最开始没想用map
弄明白数组开多大烦死了(负数可以平移)然后就用map
了。看群里讨论发现负数不一定平移,可以为负数多开一个数组记录a[-i],i<0
。
D - Colored Rectangles
首先贪心,对于每一对木条,肯定选择长的。因此先降序排列数组。
f[i][j][k]
表示:R用了i个,G用了j个,B用了k个的集合。转移考虑最后用的是那一对木棒。
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include<cstdio>
#include<string>
#include<map>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=210;
int a[N],b[N],c[N];
int f[N][N][N];
int cnta,cntb,cntc;
int main()
{IO;cin>>cnta>>cntb>>cntc;for(int i=1;i<=cnta;i++) cin>>a[i];for(int i=1;i<=cntb;i++) cin>>b[i];for(int i=1;i<=cntc;i++) cin>>c[i];sort(a+1,a+1+cnta);sort(b+1,b+1+cntb);sort(c+1,c+1+cntc);reverse(a+1,a+1+cnta);reverse(b+1,b+1+cntb);reverse(c+1,c+1+cntc);for(int i=0;i<=cnta;i++)for(int j=0;j<=cntb;j++)for(int k=0;k<=cntc;k++){if(i&&j&&(i+j+k)%2==0) f[i][j][k]=max(f[i][j][k],f[i-1][j-1][k]+a[i]*b[j]);if(j&&k&&(i+j+k)%2==0) f[i][j][k]=max(f[i][j][k],f[i][j-1][k-1]+c[k]*b[j]);if(i&&k&&(i+j+k)%2==0) f[i][j][k]=max(f[i][j][k],f[i-1][j][k-1]+a[i]*c[k]);}int res=0;for(int i=0;i<=cnta;i++) res=max(res,f[i][cntb][cntc]);for(int i=0;i<=cntb;i++) res=max(res,f[cnta][i][cntc]);for(int i=0;i<=cntc;i++) res=max(res,f[cnta][cntb][i]);cout<<res<<endl;return 0;
}
D题最后1分钟提交的太惊险了。
E-Two Types of Spells
群里大佬说是权值线段树+离散化,这个我学过补一下吧。
如果有k
个lightning
,那么能过翻倍k-1
或者k
个伤害(讨论一下),翻倍肯定翻倍最大的几个,因此考虑权值线段树(因此需要离散化)维护前k
大,一般有删除加入需要用set
维护,数据无重复,让题目简单不少。
lower_bound
只能够在升序情况下使用
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include<cstdio>
#include<string>
#include<map>
#include<set>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=200010;
int n;
pii q[N];
vector<int> id;
struct node
{int l,r,cnt;ll sum;
}tree[N*4];
int get(int a)
{int l=0,r=id.size()-1;while(l<r){int mid=l+r>>1;if(id[mid]<=a) r=mid;else l=mid+1;}return l+1;
}
void pushup(int u)
{tree[u].cnt=tree[u<<1].cnt+tree[u<<1|1].cnt;tree[u].sum=tree[u<<1].sum+tree[u<<1|1].sum;}
void build(int u,int l,int r)
{tree[u]={l,r,0,0};if(l==r) return;int mid=l+r>>1;build(u<<1,l,mid),build(u<<1|1,mid+1,r);
}
void modify(int u,int k,int x)
{if(tree[u].l==tree[u].r){tree[u].cnt+=x;tree[u].sum+=x*id[k-1];return;}int mid=tree[u].l+tree[u].r>>1;if(k<=mid) modify(u<<1,k,x);else modify(u<<1|1,k,x);pushup(u);
}
ll query(int u,int k)
{if(tree[u].l==tree[u].r) return tree[u].sum;int tmp=tree[u<<1].cnt;if(tmp>=k) return query(u<<1,k);else return tree[u<<1].sum+query(u<<1|1,k-tmp);
}
int main()
{IO;cin>>n;build(1,1,n);for(int i=1;i<=n;i++){cin>>q[i].first>>q[i].second;id.push_back(abs(q[i].second));}sort(id.begin(),id.end());id.erase(unique(id.begin(),id.end()),id.end());reverse(id.begin(),id.end());set<int> fire,lightning;int k=0;ll res=0;for(int i=1;i<=n;i++){if(q[i].first==1){if(q[i].second>0){k++;lightning.insert(q[i].second);res+=q[i].second;modify(1,get(q[i].second),1);}else{k--;lightning.erase(-q[i].second);res+=q[i].second;modify(1,get(-q[i].second),-1);}}else{if(q[i].second>0){fire.insert(q[i].second);res+=q[i].second;modify(1,get(q[i].second),1);}else{fire.erase(-q[i].second);res+=q[i].second;modify(1,get(-q[i].second),-1);}}if(fire.empty()){if(k>1)cout<<res+query(1,k-1)<<'\n';else cout<<res<<'\n';}else if(lightning.empty()) cout<<res<<'\n';else{int minl=*lightning.begin();auto t=fire.end();t--;int maxf=*t;if(minl>maxf){if(k>1) cout<<res+query(1,k-1)+maxf<<'\n';else cout<<res+maxf<<'\n';}else{if(k>0) cout<<res+query(1,k)<<'\n';else cout<<res<<'\n';}}}return 0;
}
要加油哦~