Codeforces Round #559 (Div. 2)(A,B,C)
A:
思路:首先我们必然假设初始石堆石子数为0,遇减号答案减1,遇加号答案加1,特判一下遇减号答案为0的情况,这种情况答案不增不减,只需假定初始石堆石子数多1就行了,而减完之后相当于对我们的答案贡献为0。
代码:
#include<bits/stdc++.h> using namespace std; int main(){ int i,j,k,n; cin>>n; string s; cin>>s; int ans=0; for(i=0;i<n;i++){ if(s[i]=='-')ans=ans-(ans==0?0:1); else ans++; } cout<<ans<<endl; }B:
思路:枚举所有数作为较小的那个数的情况,对于每个情况只需要考虑比这个数大的所有数里下标最小的和最大的,x/abs(pos-cur).
代码:
#include<bits/stdc++.h> using namespace std; #define inf 0x3f3f3f3f #define ll long long const ll maxn=3e5+9; struct node{ ll val,pos; bool operator <(const node &a)const{ return pos>a.pos; } }; struct nd{ ll val,pos; }a[maxn]; bool cmp(nd a,nd b){ return a.val<b.val; } set<node>st; int main(){ ll i,j,k,n; scanf("%lld",&n); for(i=1;i<=n;i++){ scanf("%lld",&a[i].val); a[i].pos=i; st.insert(node({a[i].val,a[i].pos})); } sort(a+1,a+n+1,cmp); ll ans=1e12; for(i=1;i<n;i++){ ll x=a[i].val; st.erase(node({a[i].val,a[i].pos})); auto it=*st.begin(); ans=min(ans,x/(ll)abs(a[i].pos-it.pos)); it=*(--st.end()); ans=min(ans,x/(ll)abs(a[i].pos-it.pos)); } printf("%lld\n",ans); }C:
思路:瞎搞搞就搞过了。a[i]储存的是第i个男生送给m个女生的最少糖果数,b[j]是第j个女生收到n个男生送的最大糖果数,求男生最少送了多少糖果,不妨先令ans+=a[i]*m,i=1,2,3,...,n,然后扫一遍b[j],对于每一个女生收到的最多糖果数,显然这个最多糖果数b[j],只能是a[i]<=b[j]的男生贡献的,我们已经按男生送的最少糖果初始化了答案,现在我们需要做的就是让额外花费的糖果数最少,即b[j]-a[i]最小,那么a[i]显然只能向右逼近b[j]的数,而对于a[i]我只能额外调用m-1次,因为我必须保证第i个男生送的最少糖果数不会变。然后如果女生收到的最大糖果数小于男生送出的最大的最小糖果数,输出-1
代码:
#include<bits/stdc++.h> using namespace std; #define inf 0x3f3f3f3f #define ll long long const ll maxn=1e5+9; ll a[maxn],b[maxn]; bool cmp(ll a,ll b){ return a>b; } map<long long,ll>mp; int main(){ ll i,j,k,n,m; cin>>n>>m; for(i=1;i<=n;i++){ cin>>a[i]; mp[a[i]]+=m; } for(i=1;i<=m;i++){ cin>>b[i]; } sort(a+1,a+n+1,cmp); for(i=1;i<=m;i++){ if(b[i]<a[1]){ cout<<-1<<endl; return 0; } } ll ans=0; for(i=1;i<=n;i++){ ans+=a[i]*m; mp[a[i]]--; } for(i=1;i<=m;i++){ ll x=b[i]; ll l=1,r=n+1; ll pos=lower_bound(a+1,a+n+1,x,greater<ll>())-a; if(a[pos]==x)continue; //cout<<mp[a[pos]]<<endl; while(!mp[a[pos]])pos++; ans+=x-a[pos]; mp[a[pos]]--; } cout<<ans<<endl; }
Educational Codeforces Round 65 (Rated for Div. 2)
E:
思路:首先删除完值在[L,R]范围里的数之后,我们能够发现剩下的数若要符合题意,则值在[1,L-1]里数满足下标递增,值在[R+1,x]里的数也满足下标递增,同时[1,L-1]里的数的下标都要小于[R+1,x]里的数的下标。
转换完题意之后,我们接下来要按的就是快速判断删去区间后的序列是否合法。我们可以预处理一下,找出1~i中值的最大下标和最小下标,找出1~i的前缀最大下标,i~x的后缀最小下标,然后预处理值为1~i的序列是否合法(合法代表下标递增),i~x的序列是否合法,最后用双指针找一下删除的区间然后判断一下就行了
代码:
#include<bits/stdc++.h> using namespace std; #define inf 0x3f3f3f3f const int maxn=1e6+9; bool precan[maxn],sufcan[maxn]; int premx[maxn],sufmi[maxn],posmx[maxn],posmi[maxn],a[maxn]; bool check(int l,int r){ if(!precan[l-1]||!sufcan[r+1])return false; if(premx[l-1]>sufmi[r+1])return false; //cout<<123<<endl; return true; } int main(){ int i,j,k,n,x; cin>>n>>x; memset(sufmi,inf,sizeof(sufmi)); memset(posmi,inf,sizeof(posmi)); for(i=1;i<=n;i++){ cin>>a[i]; posmx[a[i]]=max(posmx[a[i]],i); posmi[a[i]]=min(posmi[a[i]],i); } for(i=1;i<=x;i++)premx[i]=max(premx[i-1],posmx[i]); for(i=x;i>=1;i--)sufmi[i]=min(sufmi[i+1],posmi[i]); // for(i=1;i<=x;i++){ precan[0]=sufcan[x+1]=true; for(i=1;i<=x;i++){ if(posmi[i]>premx[i-1]){ precan[i]=true; // cout<<123<<endl; } else{ break; } } for(i=x;i>=1;i--){ if(posmx[i]<sufmi[i+1]){ sufcan[i]=true; } else{ break; } } long long ans=0; int r=1; for(int l=1;l<=x;l++){ if(l>r)r++; while(r<x&&!check(l,r))r++; if(check(l,r))ans+=x-r+1; } cout<<ans<<endl; }
