问题 A: 搬砖达人
根据题意,
a
n
s
=
⌊
N
W
⌋
ans=\lfloor \frac{N}{W} \rfloor
ans=⌊WN⌋
代码如下:
#include <bits/stdc++.h>
using namespace std;
signed main() {
int n,m;
scanf("%d%d",&n,&m);
cout<<n/m;
return 0;
}
问题 B: 有强迫症的搬砖达人
根据题意,
a
n
s
=
∑
i
=
1
H
∑
j
=
1
W
a
i
,
j
−
H
×
W
×
min
1
≤
i
≤
H
,
1
≤
j
≤
W
a
i
,
j
ans=\sum_{i=1}^{H}\sum_{j=1}^{W}a_{i,j}-H \times W \times \min_{1 \leq i \leq H,1 \leq j \leq W}a_{i,j}
ans=∑i=1H∑j=1Wai,j−H×W×min1≤i≤H,1≤j≤Wai,j
代码如下:
#include <bits/stdc++.h>
using namespace std;
signed main() {
int n,m,t,sum=0,minn=INT32_MAX;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf("%d",&t);
minn=min(minn,t);
sum+=t;
}
cout<<sum-minn*n*m;
return 0;
}
问题 C: 消失的星期七
观察数据范围,由于
1
≤
N
≤
1
0
5
1 \leq N \leq 10^5
1≤N≤105 ,因此依次遍历
1
1
1 ~
N
N
N ,并检查每个数是否合法即可,时间复杂度为
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
代码如下:
#include <bits/stdc++.h>
using namespace std;
signed main() {
function<bool(int)>check=[&](int x){
bool flag=1;
int y=x;
while(x&&flag)
{
flag&=(x%10!=7);
x/=10;
}
while(y&&flag)
{
flag&=(y%8!=7);
y/=8;
}
return flag;
};
int n,ans=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
ans+=check(i);
cout<<ans;
return 0;
}
问题 D: 附加题
将
N
N
N 个整数
a
i
a_i
ai 从小到大排列,则
∑
i
=
1
N
−
1
∑
j
=
i
+
1
N
∣
a
i
−
a
j
∣
=
∑
i
=
1
N
(
(
i
−
1
)
×
a
i
−
∑
j
=
1
i
−
1
a
j
)
\sum_{i=1}^{N-1}\sum_{j=i+1}^{N}|a_i-a_j|=\sum_{i=1}^{N}((i-1)\times a_i-\sum_{j=1}^{i-1}a_j)
∑i=1N−1∑j=i+1N∣ai−aj∣=∑i=1N((i−1)×ai−∑j=1i−1aj) ,遍历的同时计算前缀和,用前缀和更新答案即可
代码如下:
#include <bits/stdc++.h>
using namespace std;
signed main() {
int n;
long long sum=0,ans=0;
scanf("%d",&n);
vector<int>a(n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
sort(a.begin(),a.end());
for(int i=0;i<n;i++)
{
ans+=1ll*a[i]*i-sum;
sum+=a[i];
}
cout<<ans;
return 0;
}
问题 E: 美味佳肴
题目可转换为求方程
K
x
+
S
=
N
y
Kx+S=Ny
Kx+S=Ny 对应
x
x
x 的最小正整数解,运用拓展欧几里得解方程即可
代码如下:
#include <bits/stdc++.h>
#define int long long
#define cinout ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
int exgcd(int a,int b,int &x,int &y)
{
if(!b)
{
x=1;y=0;
return a;
}
int d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
void solve()
{
int n,s,k,x,y;
cin>>n>>s>>k;
int gcd=exgcd(n,k,x,y);
if(s%gcd)
{
cout<<"-1\n";return ;
}
n/=gcd;k/=gcd;s/=gcd;
x*=s,y*=s;
if(y>0)
y-=(y+n-1)/n*n;
else
y-=y/n*n;
cout<<-y<<"\n";
}
signed main() {
cinout;
int T=1;
cin>>T;
while(T--)
solve();
return 0;
}
问题 F: 二步棋
一共有两种方式可到达一个格子:(1)先向下再向右(2)先向右再向下
分别统计可通过两种方式中的至少一种方式到达的格子数,再减去两种方式均可到达的格子数
两种方式均可到达的格子数可用树状数组统计
代码如下:
#include <bits/stdc++.h>
using namespace std;
template <typename T>
struct Fenwick {
const int n;
std::vector<T> a;
Fenwick(int n) : n(n), a(n) {}
void add(int x, T v) {
for (int i = x; i <= n; i += i & -i) {
a[i - 1] += v;
}
}
T sum(int x) {
T ans = 0;
for (int i = x; i > 0; i -= i & -i) {
ans += a[i - 1];
}
return ans;
}
T rangeSum(int l, int r) {
return sum(r) - sum(l);
}
};
signed main() {
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int h,w,m;
cin>>h>>w>>m;
vector<int>x(m),y(m),miny(h,w),minx(w,h);
for(int i=0;i<m;i++)
{
cin>>x[i]>>y[i];
x[i]--;y[i]--;
minx[y[i]]=min(minx[y[i]],x[i]);
miny[x[i]]=min(miny[x[i]],y[i]);
}
for(int i=minx[0];i<h;i++)miny[i]=0;
for(int i=miny[0];i<w;i++)minx[i]=0;
Fenwick<int>f(w+1);
long long ans=0;
for(int i=0;i<h;i++)
ans+=miny[i];
for(int i=0;i<w;i++)
ans+=minx[i];
vector<int>pos(h);
for(int i=0;i<h;i++)pos[i]=i;
sort(pos.begin(),pos.end(),[&](int i,int j){
return miny[i]<miny[j];
});
for(int i=0,j=0;i<w;i++)
{
while(j<h&&miny[pos[j]]<=i)
f.add(pos[j++]+1,1);
ans-=minx[i]-f.sum(minx[i]);
}
cout<<ans<<"\n";
return 0;
}