A题
直接奇偶输出即可
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e5+10; int a[N]; int main(){ ios::sync_with_stdio(false); int i; int n; int t; cin>>t; while(t--){ cin>>n; for(i=1;i<=n;i++) cin>>a[i]; int l=1,r=n; for(;l<=r;l++,r--){ if(l==r){ cout<<a[l]<<" "; break; } cout<<a[l]<<" "<<a[r]<<" "; } cout<<endl; } }
B题
因为只会删中间且只会出现2020,直接暴力枚举所有情况判断
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e5+10; int a[N]; string tmp="2020"; int main(){ ios::sync_with_stdio(false); int i,j; int t; cin>>t; while(t--){ int n; cin>>n; string s; cin>>s; string d=""; if(s==tmp){ cout<<"YES"<<endl; continue; } if(s.substr(0,4)==tmp){ cout<<"YES"<<endl; continue; } if(s.substr(n-4,4)==tmp){ cout<<"YES"<<endl; continue; } d+=s[0]; d+=s.substr(n-3,3); if(d==tmp){ cout<<"YES"<<endl; continue; } d=""; d+=s.substr(0,2); d+=s.substr(n-2,2); if(d==tmp){ cout<<"YES"<<endl; continue; } d=""; d+=s.substr(0,3); d+=s.substr(n-1,1); if(d==tmp){ cout<<"YES"<<endl; continue; } cout<<"NO"<<endl; } }
C题
按序不重复枚举所有情况,暴力dfs
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e5+10; int vis[2000]; int x; int flag=0; int mi=1e9; void dfs(int u,int sum,int now){ if(sum==x){ mi=min(mi,now); flag=1; return ; } for(int i=u;i<=9;i++){ if(sum+i>x) return ; dfs(i+1,sum+i,now*10+i); } return ; } int main(){ ios::sync_with_stdio(false); int i,j; int t; cin>>t; while(t--){ cin>>x; flag=0; mi=1e9; dfs(0,0,0); if(!flag){ cout<<-1<<endl; } else{ cout<<mi<<endl; } } }
D题
区间合并,其实就是将一段和变成一个数,因此直接枚举答案到底是多少,只会不断往后维护看结果,如果合法就求min
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=3e5+10; int a[N]; ll sum[N]; int n; int ans; void check(int x,int pos){ int i,j; int cnt=pos-1; for(i=pos+1;i<=n;i++){ if(sum[i]-sum[pos]==x){ cnt+=i-pos-1; pos=i; } } if(pos==n){ ans=min(ans,cnt); } } int main(){ ios::sync_with_stdio(false); int t; cin>>t; while(t--){ cin>>n; int i; for(i=1;i<=n;i++) cin>>a[i]; for(i=1;i<=n;i++){ sum[i]=sum[i-1]+a[i]; } ans=1e9; for(i=1;i<=n;i++){ int x=sum[i]; check(x,i); } cout<<ans<<endl; } }
E1题
naotan了,没想到排序,想了一个很复杂的树状数组左右两遍并枚举情况计算
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=3e5+10; int a[N]; int tr[N]; ll l[N][10],r[N][10]; ll ans; int lowbit(int x){ return x&-x; } void add(int x,int c){ int i; for(i=x;i<N;i+=lowbit(i)){ tr[i]+=c; } } int sum(int x){ int res=0; for(int i=x;i;i-=lowbit(i)){ res+=tr[i]; } return res; } int main(){ ios::sync_with_stdio(false); int t; cin>>t; while(t--){ int n; cin>>n; int i; ans=0; for(i=0;i<=n+3;i++){ tr[i]=0; } for(i=1;i<=n;i++) cin>>a[i]; for(i=1;i<=n;i++){ l[i][1]=sum(max(a[i]-1,0))-sum(max(a[i]-3,0)); l[i][2]=sum(a[i]+2)-sum(a[i]); l[i][3]=sum(a[i])-sum(max(a[i]-2,0)); l[i][4]=sum(max(a[i]-2,0))-sum(max(a[i]-3,0)); l[i][5]=sum(a[i])-sum(max(a[i]-1,0)); l[i][6]=sum(a[i]+2)-sum(a[i]+1); l[i][7]=sum(a[i]+1)-sum(max(a[i]-1,0)); add(a[i],1); } for(i=0;i<=n+2;i++){ tr[i]=0; } for(i=n;i>=1;i--){ r[i][1]=sum(max(a[i]-1,0))-sum(max(a[i]-3,0)); r[i][2]=sum(a[i]+2)-sum(a[i]); r[i][3]=sum(a[i]+1)-sum(max(a[i]-1,0)); r[i][4]=sum(a[i]+2)-sum(a[i]+1); r[i][5]=sum(a[i])-sum(max(a[i]-1,0)); r[i][6]=sum(max(a[i]-2,0))-sum(max(a[i]-3,0)); r[i][7]=sum(a[i])-sum(max(a[i]-2,0)); add(a[i],1); } for(i=1;i<=n;i++){ ans+=l[i][1]*r[i][1]; ans+=l[i][2]*r[i][2]; ans+=l[i][3]*r[i][3]; ans+=l[i][4]*r[i][5]; ans+=l[i][5]*r[i][4]; ans+=l[i][6]*r[i][5]; ans+=l[i][5]*r[i][6]; ans+=l[i][7]*r[i][7]; ans-=l[i][5]*r[i][5]; } for(i=0;i<=n+3;i++){ tr[i]=0; } cout<<ans<<endl; } }
E2题
总结了上题的教训,发现其实顺序没有关系,因此考虑排序,二分出边界后,直接选即可
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pll; const int N=2e5+10; const int mod=1e9+7; int n,m,k; int c[N][101]; int a[N]; void init(){ int i,j; for(i=0;i<=200010;i++){ for(j=0;j<=i&&j<=100;j++){ if(!j) c[i][j]=1; else c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod; } } } int main(){ ios::sync_with_stdio(false); int t; cin>>t; init(); while(t--){ cin>>n>>m>>k; int i; ll ans=0; for(i=1;i<=n;i++){ cin>>a[i]; } sort(a+1,a+1+n); for(i=1;i<=n;i++){ int l=1,r=i; while(l<r){ int mid=l+r>>1; if(a[i]-a[mid]<=k){ r=mid; } else l=mid+1; } ans=(ans+c[i-l][m-1])%mod; } cout<<ans<<endl; } return 0; }
F题
首先显然答案是其中一条线段,因此我们考虑枚举,首先关注到数据比较大,直接离散化。
之后是常规套路,可以考虑枚举线段,那么对于这条线段,不合法的情况就是左端点在当前右端点右边的答案和右端点在当前左端点左边的答案
对于第二种,可以使用差分维护,然后我们再维护一个前缀数组和后缀数组表示答案,之后就可以枚举取min了
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pll; const int N=5e5+10; vector<int> num; vector<int> g[N]; int l[N],r[N]; int sum[N]; int pre[N],suf[N]; int find(int x){ return lower_bound(num.begin(),num.end(),x)-num.begin()+1; } int main(){ ios::sync_with_stdio(false); int t; cin>>t; while(t--){ int n; cin>>n; int i; num.clear(); for(i=1;i<=n;i++){ cin>>l[i]>>r[i]; num.push_back(l[i]); num.push_back(r[i]); } sort(num.begin(),num.end()); num.erase(unique(num.begin(),num.end()),num.end()); for(i=1;i<=n;i++){ l[i]=find(l[i]); r[i]=find(r[i]); g[l[i]].push_back(r[i]); sum[l[i]]++,sum[r[i]+1]--; } int ans=1e9; for(i=1;i<=(int)num.size();i++){ sum[i]+=sum[i-1]; } for(i=1;i<=(int)num.size();i++){ pre[i]=pre[i-1]+(int)g[i].size(); } suf[(int)num.size()+1]=0; for(i=(int)num.size();i>=1;i--){ suf[i]=suf[i+1]+(int)g[i].size(); } for(i=(int)num.size();i>=1;i--){ for(auto x:g[i]){ ans=min(ans,pre[i-1]-(sum[i]-(int)g[i].size())+suf[x+1]); } } cout<<ans<<endl; for(int i=0;i<=(int)num.size()+2;i++){ g[i].clear(); sum[i]=0; } } return 0; }