[ABC331A] Tomorrow
题意简述
在 ATC 王国,一年有 M M M 月,一月有 D D D 天。若今天的日期是 a a a 年 b b b 月 c c c 天,明天的日期是多少?
代码示例
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,a,b,c,x,y;
signed main(){
cin>>x>>y>>a>>b>>c;
if(b==x&&c==y) b=1,c=1,a++;
else if(c==y) c=1,b++;
else c++;
cout<<a<<" "<<b<<" "<<c<<endl;
return 0;
}
[ABC331B] Buy One Carton of Milk
题意简述
买 6 6 6 个鸡蛋需要 a a a 元,买 8 8 8 个鸡蛋需要 b b b 元,买 12 12 12 个鸡蛋需要 c c c 元,现在需要至少 n n n 个鸡蛋,最少需要花多少钱?
解题思路
n n n 极小,只有 100 100 100,所以直接枚举即可。
代码示例
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,a,b,c,ans=0x3f3f3f3f3f3f3f3f;
signed main(){
cin>>n>>a>>b>>c;
for(int i=0;i<=n;i++){
for(int j=0;j<=100;j++){
for(int k=0;k<=100;k++){
if(i*6+j*8+k*12>=n) ans=min(ans,i*a+j*b+k*c);
}
}
}
cout<<ans<<endl;
return 0;
}
[ABC331C] Sum of Numbers Greater Than Me
题意简述
给定 n n n 个数,对于每个 i i i,输出所有大于 a i a_i ai 的数的和。
做题思路
将 a a a 数组复制到 c n t cnt cnt 中,然后对 c n t cnt cnt 进行排序,用 s u m sum sum 对 c n t cnt cnt 求前缀和。对于每个 a i a_i ai,二分找它在 c n t cnt cnt 中的位置,然后用前缀和相减得出答案。
代码示例
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,a[200010],sum[200010],cnt[200010];
signed main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],sum[i]=a[i],cnt[i]=a[i];
sort(cnt+1,cnt+n+1);
for(int i=1;i<=n;i++) sum[i]=sum[i-1]+cnt[i];
for(int i=1;i<=n;i++){
int id=upper_bound(cnt+1,cnt+n+1,a[i])-cnt;
id--;
cout<<sum[n]-sum[id]<<" ";
}
return 0;
}
[ABC331D] Tile Pattern
题意简述
给定一个由黑白格子构成的矩形,然后将这个矩形复制无数多次,相互对齐拼接起来,得到一个无限大平面。再给定 q q q 次询问,每次询问给定一个左上角和右下角,求这个矩形范围内有多少个黑格。
解题思路
首先对给定的矩形做一个二维前缀和,方便直接算出来答案。
一种方法是利用容斥。
定义 s u m ( x , y ) sum(x,y) sum(x,y) 为 ( 1 , 1 ) (1,1) (1,1) 到 ( x , y ) (x,y) (x,y) 的范围内的黑格数量。答案显然就是和二维前缀和一样的容斥。但是注意询问的范围可能很大,所以需要算一下其中包含了多少个基准矩形,再乘上基准矩形的答案。
另一种方法是我的赛时做法,非常愚蠢,还把横纵搞反了导致我调了二十分钟。我们直接把基准矩形定义为以询问的左上角为顶点的 n × n n \times n n×n矩形,然后跟上面一样算就可以。
思考一下这种方法的本质是什么。是以询问的左上角为基准,重新找到一个基准矩形,重新构造一个无限大平面,那么构造完了之后询问的矩形很显然就位于 ( 1 , 1 ) (1,1) (1,1) 这个点了。
下面的代码是我的赛时解法。
代码示例
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,q,xxxx[20][20]={0},sum[2010][2010];
//小寄巧:xxxx数组是为了防止sum越界的。
//底下的for循环会遍历到sum[-1][-1]
//但是sum前面放上一个数组就不会RE
string s[2010];
int getans(int x,int y,int l1,int l2){
//x,y是左上角位置,l1,l2是长和宽
if(l1==0||l2==0) return 0;
return sum[x+l1-1][y+l2-1]-sum[x-1][y+l2-1]-sum[x+l1-1][y-1]+sum[x-1][y-1];
}
signed main(){
cin>>n>>q;
for(int i=0;i<n;i++) cin>>s[i],s[i]+=s[i];
for(int i=n;i<2*n;i++) s[i]=s[i-n];
for(int i=0;i<2*n;i++){
for(int j=0;j<2*n;j++) sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+(s[i][j]=='B');
}
//处理 (2*n)*(2*n)的矩形答案,方便计算
while(q--){
int a,b,c,d,ans=0;
cin>>a>>b>>c>>d;
c-=a/n*n;
d-=b/n*n;
b%=n;
a%=n;
ans+=((c-a+1)/n)*((d-b+1)/n)*(getans(a,b,n,n));
ans+=((d-b+1)/n)*(getans(a,b,(c-a+1)%n,n));
ans+=((c-a+1)/n)*(getans(a,b,n,(d-b+1)%n));
ans+=getans(a,b,(c-a+1)%n,(d-b+1)%n);
cout<<ans<<endl;
}
return 0;
}
[ABC331E] Set Meal
题意简述
有 n n n 道主菜,第 i i i 道价格为 a i a_i ai。有 m m m 道小菜,第 i i i 道价格为 b i b_i bi。定义一个套餐为一份主菜加一份小菜。给定 m m m 种不可行的套餐,求出剩余套餐中最贵的要花多少钱。
解题思路
不可行的套餐总数只有 m m m,不会太多,所以遍历每一道主菜,遍历的时候我们按以下三步走:
将对于这道主菜而言不可行的小菜删掉。
统计答案。
将删掉的小菜加回去。
将所有小菜丢到一个可重集里,执行以上操作就可以了。
代码示例
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m,l,a[2000010],b[2000010],c[2000010],d[2000010],ans=0;
multiset<int> s;
vector<int> G[2000010];
signed main(){
cin>>n>>m>>l;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=m;i++) cin>>b[i],s.insert(b[i]);
for(int i=1;i<=l;i++) cin>>c[i]>>d[i],G[c[i]].push_back(d[i]);
for(int i=1;i<=n;i++){
for(int v:G[i]) s.erase(s.find(b[v]));
if(!s.empty()) ans=max(ans,a[i]+*s.rbegin());
//不判非空=RE一发 :(
for(int v:G[i]) s.insert(b[v]);
}
cout<<ans<<endl;
return 0;
}