Codeforces div2 C题补题
1922 C. Closest Cities
很容易看出,端点的两个城市的最近城市就是他的直接后继和直接前驱,而中间的城市的最近城市就是他前驱和后继中距离绝对值最小的那个,因此我们可以先预处理出每个城市对应的最近城市,用map存储。
然后因为区间可以从左向右走也可以从右向左走,因此我们可以求出其前缀后缀和,前缀和表示从左向右的花费总和,后缀和表示从右向左的花费总和,在求前缀后缀和的时候,下一个如果恰好是距离最近的城市,我们就贪心地直接花费1块钱直接去那,否则就花费其距离的绝对值。
这样的话我们在进行询问的时候直接\(pre[r]-pre[l]\)就可以\(O(1)\)求出l到r的最短距离了
AC代码:
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define int long long
using ull = unsigned long long;
using ll = long long;
using i128 = __int128_t;
using pii = pair<int,int>;
using psi = pair<string,int>;
constexpr ll MOD = 1e9+7;
//-------------------------------------------------------->>>>>>>>>>
inline void solve(){
int n;
cin>>n;
vector<int> a(n+1,0);
map<int,int> nest;
for(int i=1;i<=n;i++){
cin>>a[i];
}
nest[1]=2;
nest[n]=n-1;
for(int i=2;i<n;i++){
if(abs(a[i-1]-a[i])<abs(a[i+1]-a[i])){
nest[i]=i-1;
}else{
nest[i]=i+1;
}
}
vector<int> pre(n+1,0);
pre[1]=0;
for(int i=2;i<=n;i++){
if(i==nest[i-1]){
pre[i]=pre[i-1]+1;
}else{
pre[i]=pre[i-1]+abs(a[i]-a[i-1]);
}
}
vector<int> suf(n+2,0);
suf[n]=0;
for(int i=n-1;i>=1;i--){
if(i==nest[i+1]){
suf[i]=suf[i+1]+1;
}else{
suf[i]=suf[i+1]+abs(a[i]-a[i+1]);
}
}
int m;
cin>>m;
while(m--){
int l,r;
cin>>l>>r;
if(l>r) cout<<suf[r]-suf[l]<<"\n";
else cout<<pre[r]-pre[l]<<"\n";
}
}
inline void prework(){
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
cout<<fixed<<setprecision(12);
prework();
int T=1;
cin>>T;
while(T--){
solve();
}
return 0;
}
1895 C. Torn Lucky Ticket
从字符串的最大长度不超过5可以猜到一定是可以枚举长度的,我们可以先把每个字符串\(str_i\)的数位总和和长度记录下来,用map存储,然后枚举\(str_i\)看\(str_i\)能够与哪些字符串构成符合要求的数字,然后枚举\(str_i\)的长度cnt作为其左半部分,这样的话右半部分剩余的长度就是\(rem=str_i.size()-cnt\),需要补足的长度就是\(cnt-rem\),这样我们之前存储的map就有用了,我们可以根据其总和和长度判断是否存在,有几个这样的字符串合法,\(mp[\{cnt-rem,pre-(tot-pre)\}]\),pre是枚举到字符串前i个字符的数位总和,这样便可以获取数量,因为可以左右拼也可以右左拼,所以还要再反向处理一遍,注意的是,因为可以和自己拼,所以前后各走一遍会重复,所以当枚举长度等于字符串长度时,加一遍就行了。
AC代码如下:
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define int long long
using ull = unsigned long long;
using ll = long long;
using i128 = __int128_t;
using pii = pair<int,int>;
using psi = pair<string,int>;
constexpr ll MOD = 1e9+7;
//-------------------------------------------------------->>>>>>>>>>
inline void solve(){
int n;
cin>>n;
vector<string> a(n);
for(int i=0;i<n;i++){
cin>>a[i];
}
map<pii,int> tok;
for(int i=0;i<n;i++){
int tot=0;
for(int j=0;j<a[i].size();j++){
tot+=a[i][j]-'0';
}
tok[{a[i].size(),tot}]++;
}
int ans=0;
for(int i=0;i<n;i++){
int tot=0;
for(int j=0;j<a[i].size();j++){
tot+=a[i][j]-'0';
}
int cnt=0;
int pre=0,suf=0;//pre从前向后,suf从后向前
for(int j=0;j<a[i].size();j++){
cnt++;
pre+=a[i][j]-'0';
suf+=a[i][a[i].size()-j-1]-'0';
int rem=a[i].size()-cnt;
ans+=tok[{cnt-rem,2*pre-tot}];
if(!(j==a[i].size()-1)){//如果j=a.size,suf就不累计进去了
ans+=tok[{cnt-rem,2*suf-tot}];
}
}
}
cout<<ans<<"\n";
}
inline void prework(){
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
cout<<fixed<<setprecision(12);
prework();
int T=1;
// cin>>T;
while(T--){
solve();
}
return 0;
}
1904 C. Array Game
分类讨论,双指针
可以发现,当\(m\ge 3\)时一定为0,因为可以随便选择两个数字处理两次得到两个相同的数,再将这两个数相减,就一定是0
当m=1时,直接\(O(n^2)\)枚举就行,因为n很小
当m=2时,先排序,再用双指针求最小值就行,之前用了\(map<int,vector<int>>\)存储,虽然也是\(O(n^2)\)复杂度,但会MLE。
注意要先把原数组扫一遍取最小值
AC代码:
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f3f3f3f3f
#define int long long
using ull = unsigned long long;
using ll = long long;
using i128 = __int128_t;
using pii = pair<int,int>;
using psi = pair<string,int>;
constexpr ll MOD = 1e9+7;
//-------------------------------------------------------->>>>>>>>>>
inline void solve(){
int n,m;
cin>>n>>m;
vector<int> a(n);
for(int i=0;i<n;i++){
cin>>a[i];
}
if(m>=3){
cout<<0<<"\n";
return;
}
int maxn=INF;
if(m==2){
int ans = INF;
sort(all(a));
for (int j = 0; j < n; j++){
ans = min(ans, a[j]);
}
for (int j = 0; j < n; j++){
int p = 0;
for (int l = j + 1; l < n; l++){
while (p < n){
if (a[p] < a[l] - a[j]){
p++;
} else {
break;
}
}
ans = min(ans, a[l] - a[j]);
if (p > 0){
ans = min(ans, (a[l] - a[j]) - a[p - 1]);
}
if (p < n){
ans = min(ans, a[p] - (a[l] - a[j]));
}
}
}
cout << ans << "\n";
return;
}
if(m==1){
for (int j = 0; j < n; j++){
maxn = min(maxn, a[j]);
}
for(int i=1;i<n;i++){
for(int j=0;j<i;j++){
maxn=min(maxn,abs(a[j]-a[i]));
}
}
cout<<maxn<<"\n";
return;
}
}
inline void prework(){
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
cout<<fixed<<setprecision(12);
prework();
int T=1;
cin>>T;
while(T--){
solve();
}
return 0;
}
标签:pre,suf,int,ll,Codeforces,long,补题,using,div2
From: https://www.cnblogs.com/KrowFeather/p/18010281