@[toc](Panasonic Programming Contest (AtCoder Beginner Contest 186))
导读:
简单的题目,只说明题意,或者直接说明结论
下面的难题,会做详细的解释和证明
立个flag,在座的大佬们做个见证:一个月刷60场ABC,现在2021/7/3,第十八天,已打卡十四场。
A - Brick
求下取整
void work()
{
int a, b; cin >> a >> b;
cout << a / b << endl;
}
B - Blocks on Grid
删去一些格子,让所有位置的高度相同
void work()
{
int n, m; cin >> n >> m;
int g[110][110] = {0};
int h = 1e9;
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
{
cin >> g[i][j];
h = min(h, g[i][j]);
}
int sum = 0;
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
sum += g[i][j] - h;
cout << sum << endl;
}
C - Unlucky 7
问从1到n,有多少个数,他的十进制和八进制的每一位都没有7的数字有多少个
void work()
{
int n; cin >> n;
int sum = 0;
for (int i = 1; i <= n; i ++ )
{
//十进制
int t = i;
bool flag = true;
while (t)
{
if (t % 10 == 7)
{
sum ++;
flag = false;
break;
}
t /= 10;
}
//八进制
t = i;
while (t && flag)
{
if (t % 8 == 7)
{
sum ++;
break;
}
t /= 8;
}
}
cout << n - sum << endl;
}
D - Sum of difference
首先,给数列按照从大到小排个序,将绝对值拿掉。然后,将式子展开,给每个位置补上一个|啊|aii - aii|,然后观察式子发现这就是一个前缀和处理的问题。
#include <bits/stdc++.h>
using namespace std;
const int N = 200010;
int n;
long long a[N], s[N];
int main()
{
cin >> n;
for (int i = 1; i <= n; i ++ )
scanf("%lld", &a[i]);
sort(a + 1, a + 1 + n);
reverse(a + 1, a + 1 + n);
for (int i = 1; i <= n; i ++ )
s[i] = s[i - 1] + a[i];
// for (int i = 1; i <= n; i ++ ) cout << a[i] << " "; cout << endl;
// for (int i = 1; i <= n; i ++ ) cout << s[i] << " "; cout << endl;
reverse(s + 1, s + 1 + n);
long long sum = 0;
reverse(a + 1, a + 1 + n);
for (int i = 1; i <= n; i ++ )
{
sum += s[i] - (n - i + 1) * a[i];
}
cout << sum << endl;
return 0;
}
E - Throne
题意:在一个圆上,王座在位置0,当前位置在S,我们每次走k步,问最少多少步可以到达0
也就是x*k % N = (N - s) % N
#include <bits/stdc++.h>
using namespace std;
long long exgcd(long long a, long long b, long long&x, long long& y)
{
if (b == 0)
{
x = 1, y = 0;
return a;
}
long long d = exgcd(b, a % b, y, x);
y = y - a / b * x;
return a;
}
void work()
{
long long n, s, k; cin >> n >> s >> k;
long long d = __gcd(n, __gcd(s, k));
n /= d; s /= d; k /= d;
long long x, y;
if (__gcd(k, n) == 1)
{
long long ans = exgcd(k, n, x, y);
x = (n + x % n) % n;
ans = n - x * s % n;
cout << ans << endl;
}
else
{
cout << "-1" << endl;
}
}
int main()
{
int T; cin >> T;
while (T -- ) work();
return 0;
}
F - Rook on Grid
从第一行开始枚举每一行,直到i=n,结束枚举
将每个点按照以行为第一关键字,列为第二关键字,按照从小到大的顺序排序,方便枚举
将第一行第一次出现g[1][j]=1的后面的所有格点都给标记g[1][j] = 1
将第一列第一次出现g[i][1]=1的后面的所有格点都给标记g[i][1] = 1
找到当前行的第一个g[i][j] = 1,s[m] - s[j - 1]就是当前行的个数,同时,标记当前行每个1
然后将每一行加在一起
这样,单点修改区间查询,可以使用树状数组
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 200010;
#define lowbit(x) x & -x
int n, m, k;
ll tr[N];
bool st[N];
vector<int> g[N];
void add(int x, int c)
{
for (; x <= m; x += lowbit(x) ) tr[x] += c;
}
ll query(int x)
{
ll ans = 0;
for (; x; x -= lowbit(x)) ans += tr[x];
return ans;
}
int main()
{
scanf("%d%d%d", &n, &m, &k);
int x, y, minx = 1e9, miny = 1e9;
for (int i = 0; i < k; i ++ )
{
scanf("%d%d", &x, &y);
if (x == 1) miny = min(miny, y);
if (y == 1) minx = min(minx, x);
g[x].push_back(y);
}
if (miny < 1e9) for (int j = miny + 1; j <= m; j ++ ) g[1].push_back(j);
if (minx < 1e9) for (int i = minx + 1; i <= n; i ++ ) g[i].push_back(1);
for (int i = 1; i <= n; i ++ ) sort(g[i].begin(), g[i].end());
ll ans = 0;
for (int i = 1; i <= n; i ++ )
{
if (g[i].size() == 0) continue;
for (int y : g[i]) if (!st[y]) st[y] = true, add(y, 1);
ans += query(m) - query(g[i][0] - 1);
}
cout << 1ll * n * m - ans << endl;
return 0;
}