官方题解:https://codeforces.com/blog/entry/84847
A - Robot Program
要到达终点的最短路径,一定是要么不用West,要么不用North,并且,其指令序列一定为E x E x E x……x E或者S x S x S x……x S交错排成,因此,我们可以得到结论答案为max(x,y)*2,并且当x==y的时候,S(E)与x数量相同,需要+1。
t=input()
t=int(t)
while t>0:
t-=1
x,y=input().split()
x=int(x)
y=int(y)
ans=max(x,y)*2
if(x!=y):ans-=1
print(ans)
B - Toy Blocks
由于拿了第i个箱子之后,都是剩下n-1个箱子,并且,因为第i个箱子的物品被分给其他箱子,所以总数一直为sum,并且平均分后每个箱子为sum/(n-1)个物品,因此,我们可以二分平均分后的物品为ans,则,ans满足:ans>=max(a[i])并且(n-1)*ans>=sum。注意r需要开到2e9。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);++i)
#define per(i,a,b) for(int (i)=(b);(i)>=(a);--i)
template<typename T>
void read(T&x){
x=0;
ll f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')f*=-1;
ch=getchar();
}
while(isdigit(ch)){
x=x*10+ch-'0';
ch=getchar();
}
}
template<typename T>
void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9) write(x/10);
putchar(x%10+'0');
}
//===============================================
#define int ll
const int maxn=1e5+100;
int t,n;
ll a[maxn];
ll sum=0,mx;
bool check(ll x){
return (n-1)*x>=sum&&x>=mx;
}
int solve(){
sum=0,mx=0;
rep(i,1,n){
sum+=a[i];
mx=max(mx,a[i]);
}
ll l=mx,r=2e9+100;
while(l<=r){
ll m=(l+r)>>1;
if(check(m)){
r=m-1;
}
else{
l=m+1;
}
}
return (n-1)*(r+1)-sum;
}
signed main(){
read(t);
while(t--){
read(n);
rep(i,1,n)read(a[i]);
write(solve());putchar('\n');
}
return 0;
}
C - Two Brackets
这题会联想到数据结构课上讲的栈和括号序列的应用,并且由于这题不需要连续的,因此,我们可以对这个算法进行变形:当遇到左括号时,将他压入栈中。当遇到右括号时候,若此时栈中有左括号,则pop一个,统计答案。否则,我们直接忽略他(因为此时左边无剩余的左括号,无法搭配删除)。返回统计答案即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);++i)
#define per(i,a,b) for(int (i)=(b);(i)>=(a);--i)
template<typename T>
void read(T&x){
x=0;
ll f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')f*=-1;
ch=getchar();
}
while(isdigit(ch)){
x=x*10+ch-'0';
ch=getchar();
}
}
template<typename T>
void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9) write(x/10);
putchar(x%10+'0');
}
//===============================================
#define int ll
const int maxn=2e5+100;
int t;
char str[maxn];
ll solve(){
int len=strlen(str+1);
int pos1,pos2;
pos1=pos2=0;
int ans=0;
rep(i,1,len){
if(str[i]=='[')pos1++;
if(str[i]=='(')pos2++;
if(str[i]==']'){
if(pos1)pos1--,ans++;
}
if(str[i]==')'){
if(pos2)pos2--,ans++;
}
}
return ans;
}
signed main(){
//freopen("in.txt","r",stdin);
read(t);
while(t--){
scanf("%s",str+1);
write(solve());putchar('\n');
}
return 0;
}
D - Radio Towers
听轩哥的就对了:https://blog.csdn.net/weixin_46163391/article/details/109877652
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);++i)
#define per(i,a,b) for(int (i)=(b);(i)>=(a);--i)
template<typename T>
void read(T&x){
x=0;
ll f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')f*=-1;
ch=getchar();
}
while(isdigit(ch)){
x=x*10+ch-'0';
ch=getchar();
}
}
template<typename T>
void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9) write(x/10);
putchar(x%10+'0');
}
//===============================================
const int maxn=2e5+100;
ll mod=998244353;
ll ksm(ll a,ll n){
ll res=1;
while(n){
if(n&1) res=res*a%mod;
a=a*a%mod;
n>>=1;
}
return res;
}
ll n;
ll f[maxn];
ll solve(){
ll fm=ksm(ksm(2,n),mod-2)%mod;
f[1]=1;
f[2]=1;
rep(i,3,n){
f[i]=(f[i-1]+f[i-2])%mod;
}
return f[n]*fm%mod;
}
int main(){
//freopen("in.txt","r",stdin);
read(n);
write(solve());
return 0;
}
E - Two Editorials
暴力的方法是:枚举两个出题人的起点,之后枚举任务,统计贡献,复杂度O(mn^2)
考虑优化统计第二个出题人的贡献:如果能够在枚举统计第一个出题人贡献的时候,O(1)查询此时第二个出题人的贡献,则复杂度能够降到O(nm)。
考虑开数组计下第二个出题人的贡献。不妨设第一个出题人选的区间在前,第二个出题人选的区间在后。
此时,我们需要先定义“前”和“后”:我们选择根据区间的中点位置的前后定义前后,原因如下:
设出题人选择的区间为S,目前一个题目的区间为T,通过观察,我们可以知道:两个区间中点越靠近,则相交区域越大(不一定是严格增大)。因此,我们可以通过中点定义区间前后。
我们根据前后顺序对m个区间sort一次。
之后,我们计算第二个出题人的贡献。数组val[i]表示第二个出题人从i~m个区间(后缀)内选择,最大的贡献。之后,我们还是要枚举第二个出题人的起点,去更新val[i]。
之后,我们枚举第一个出题人的起点,从前向后枚举每个问题区间(前缀),计算从1~j范围内第一个出题人的贡献,再加上刚才计算的j+1~m区间内第二个出题人的贡献,就是两人的总贡献。
这里有个疑问:题目里,教练只会选择能给他们尽量多的出题人去听,而我们的模拟过程并没有看到和这个相关的部分。
我的理解是:我们枚举第一个出题人的起点计算贡献时,是计算了1~i的贡献,然后,数组里记下了是i+1~m的贡献,若区间i+1与第一个出题人的交集更大,那等会枚举到i+1任务的时候这个方案是更优的,所以,不会对最后结果产生影响,因此,这个算法是正确的。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);++i)
#define per(i,a,b) for(int (i)=(b);(i)>=(a);--i)
template<typename T>
void read(T&x){
x=0;
ll f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')f*=-1;
ch=getchar();
}
while(isdigit(ch)){
x=x*10+ch-'0';
ch=getchar();
}
x*=f;
}
template<typename T>
void write(T x){
if(x<0)x=-x,putchar('-');
if(x>9) write(x/10);
putchar(x%10+'0');
}
//=====================================================
#define int ll
const int maxn=2e3+100;
struct node{
int l,r;
}da[maxn];
int val[maxn];
int n,m,k;
int solve(){
sort(da+1,da+1+m,[](const node&a,const node&b){
return a.l+a.r<b.l+b.r;
});
rep(l,1,n-k+1){
int r=l+k-1;
int pos=0;
per(j,1,m){
pos+=(max(min(da[j].r,r)-max(da[j].l,l)+1,0ll));
val[j]=max(val[j],pos);
}
}
int res=0;
rep(l,1,n-k+1){
int r=l+k-1;
int pos=0;
rep(j,1,m){
pos+=max(min(da[j].r,r)-max(da[j].l,l)+1,0ll);
res=max(res,pos+val[j+1]);
}
}
return res;
}
signed main(){
//freopen("in.txt","r",stdin);
read(n),read(m),read(k);
rep(i,1,m){
read(da[i].l),read(da[i].r);
}
write(solve());
return 0;
}