[题解][SDCPC 2019] 第十届山东省 ICPC 大学生程序设计竞赛
补题中。
参考:https://sua.ac/wiki/2019-provincial-shandong/
A - Calandar
两日期相差的天数是 \(\Delta d+30\Delta m+360\Delta y\),取模即可。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int t,y,m,d,yy,mm,dd;
string s,nam[5]{"Monday","Tuesday","Wednesday","Thursday","Friday"};
map<string,int> ma;
inline int calc(){return (dd-d)+30*(mm-m)+360*(yy-y);}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
for(int i=0;i<5;i++) ma[nam[i]]=i;
cin>>t;
while(t--){
cin>>y>>m>>d>>s>>yy>>mm>>dd;
cout<<nam[(ma[s]+calc()%5+5)%5]<<"\n";
}
return 0;
}
B - Flipping Game
C - Wandering Robot
可以发现,第 \(1,2,\dots,k\) 轮的第 \(i\) 次移动结束后,到达的位置构成一条线段,而这条线段上的点到原点的曼哈顿距离构成的函数图像一定是先减后增的(因为 \(|x|,|y|\) 均呈 V 字形,加起来就是开口向上的碗形)。
所以最大值一定由第 \(1\) 轮或者第 \(k\) 轮取到。仅需模拟这两轮的位置即可。
时间复杂度 \(O(n)\)。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
int t,n,k,d[N],dx[4]{0,1,0,-1},dy[4]{1,0,-1,0};
string s;
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>t;
while(t--){
cin>>n>>k>>s;
int ans=0,x=0,y=0,xx=0,yy=0;
for(int i=0;i<n;i++){
d[i+1]=(s[i]=='U')+(s[i]=='R')*2+(s[i]=='D')*3+(s[i]=='L')*4-1;
}
for(int i=1;i<=n;i++) xx+=dx[d[i]],yy+=dy[d[i]];
xx*=k-1,yy*=k-1;
ans=max(ans,abs(xx)+abs(yy));
for(int i=1;i<=n;i++){
x+=dx[d[i]],y+=dy[d[i]];
ans=max({ans,abs(x)+abs(y),abs(x+xx)+abs(y+yy)});
}
cout<<ans<<"\n";
}
return 0;
}
D - Game on a Graph
E - BaoBao Loves Reading
还没写代码,口胡一下。
令 \(lst_i\) 为 \(a_i\) 上一次出现的位置(没有则为 \(0\))。
显然,\(i\) 不会重新被取出,当且仅当 \([lst_i+1,i]\) 中不同值的个数(记为 \(x\))\(\le k\)。
换句话说,对于下标 \(i\),它会对 \(k=1,2,\dots,x\) 的答案各产生 \(1\) 的贡献。
区间不同值的个数可以看 P1972,各种方法均可求解。
F - Stones in the Bucket
二分最终合并到的高度。
时间复杂度 \(O(n\log V)\)。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
int t,n,a[N];
inline int calc(int x){
int s=0,t=0;
for(int i=1;i<=n;i++){
if(a[i]>x) s+=a[i]-x;
else t+=x-a[i];
}
return s>=t?s:-1;
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>t;
while(t--){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
int l=0,r=1e9+10;
while(l<r){
int mid=(l+r+1)>>1;
if(~calc(mid)) l=mid;
else r=mid-1;
}
cout<<calc(l)<<"\n";
}
return 0;
}
还有线性解法,之后会补。
G - Heap
H - Tokens on the Segments
贪心。按左端点排序,枚举每一个位置,若能放置则优先选择右端点最小的。
可以用优先队列完成。
时间复杂度 \(O(n\log n)\)。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
priority_queue<int,vector<int>,greater<int>> q;
struct Seg{int l,r;}s[N];
int t,n;
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>t;
while(t--){
int ans=0;
cin>>n;
for(int i=1;i<=n;i++) cin>>s[i].l>>s[i].r;
sort(s+1,s+1+n,[](Seg a,Seg b){return a.l<b.l;});
s[n+1].l=INT_MAX;
for(int i=1;i<=n;i++){
q.push(s[i].r);
for(int k=s[i].l;k<s[i+1].l;k++){
while(!q.empty()&&q.top()<k) q.pop();
if(q.empty()) break;
q.pop();
ans++;
}
}
cout<<ans<<"\n";
}
return 0;
}
浙公网安备 33010602011771号