Panasonic Programming Contest (AtCoder Beginner Contest 186)

A

1
2
3
4
5
6
7
8
9
10
11
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e6+100;
int main()
{
int n,m;
cin>>n>>m;
cout<<n/m;
return 0;
}

B

求出最小值,然后减去

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e6+100;
int mp[105][105];
int main()
{
int mx = 99999999;
int n, m; cin >> n >> m;
for(int i = 1;i <= n; i++) {
for(int j = 1;j <= m; j++) {
cin >> mp[i][j];
mx = min(mx, mp[i][j]);
}
}
ll ans = 0;
for(int i = 1;i <= n; i++) {
for(int j = 1;j <= m; j++) {
ans += mp[i][j] - mx;
}
}
cout << ans;

}

C

直接分解10和分解8然后判断会不会出现7

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e6+100;
//数字很小,直接拆就行
int main()
{
int n; cin >> n;
ll ans = n;
for(int i = 7;i <= n; i++) {
int tt = i;
bool flag1 = 0;
while(tt) {
if(tt % 10 == 7) {
flag1 = 1;
break;
}
tt /= 10;
}
tt = i;
bool flag2 = 0;
while(tt) {
if(tt % 8 == 7) {
flag2 = 1;
break;
}
tt /= 8;
}
if(flag1 || flag2) ans--;
}
cout << ans << endl;


}

D

排序不影响,排序后求一个前缀和就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e6+100;
//很明显排序并不会影响结果
ll a[N];
ll ans;
ll sum[N];
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
sort(a+1,a+1+n);
for(int i=1;i<=n;i++)
{
sum[i]=sum[i-1]+a[i];
}
for(int i=1;i<n;i++)
{
ans+=(sum[n]-sum[i])-(n-i)*a[i];
}
cout<<ans;
}

E

由于可以转化为同余问题,就扩展欧几里得直接解决即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// LUOGU_RID: 156505088
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e6+100;
//不断加一个数字取模康康会不会相等
//有趣的东西
//感觉数学
//(k*x+s)%n==0
//找出最小x
//移动变成kx==n-s(%n)
//同余方程
//板子题了已经
ll x,y;
ll exgcd(const ll &a,const ll &b)
{
if(!b)
{
x=1;
y=0;
return a;
}
ll d=exgcd(b,a%b);
ll z=x;
x=y;
y=z-y*(a/b);
return d;
}
int main()
{
int t;
cin>>t;
while(t--)
{
ll a,b,s;
cin>>b>>s>>a;
ll g=exgcd(a,b),t=(b-s)%b;
if(t%g)
{
cout<<-1<<'\n';
}
else
{
cout<<(x%b+b)%b*(t/g)%(b/g)<<'\n';
}
}
}

F

显然要维护: r[i]=第i行第一个障碍的下标, c[i]=第i列第一个障碍的下标.

对于[1,c[1]-1]的每一行,显然答案累加r[i]-1, 对于[1,r[1]-1]的每一列,显然答案累加c[i]-1, 但是这样会统计到之前统计过的格子,考虑如何消去重复: 对于第i列,本来应该累加c[i]-1, 重复格子的个数就是1到c[i]-1行中r[]>i的行的数量, 那么不重复格子的数量就是1到c[i]-1行中r[]<=i的行的数量. 如何统计? 上面的条件是r[]<=i,发现i是递增的, 因此将(r[k],k)按照第一维r[]从小到大排序, 枚举列i的时候,只需要查询r[]<=i的(r[k],k)中, 有多少个满足k满足<=c[i]-1即可, 可以用树状数组存k, 查询的时候直接查询[1,c[i]-1]的前缀和即可.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2e6+5;
vector<ll>g[N];
ll r[N],c[N];
ll n,m,w;
struct BIT
{
ll c[N];
int lowbit(ll i)
{
return i&(-i);
}
void add(ll i,ll t)
{
while(i<N)
{
c[i]+=t;
i+=lowbit(i);
}
}
int ask(ll i)
{
ll res=0;
while(i)
{
res+=c[i];
i-=lowbit(i);
}
return res;
}
}T;
ll ans;
int main()
{
cin>>n>>m>>w;
for(int i=1;i<=n;i++)
{
r[i]=m+1;
}
for(int i=1;i<=m;i++)
{
c[i]=n+1;
}
for(int i=1;i<=w;i++)
{
ll x,y;
cin>>x>>y;
r[x]=min(r[x],y);
c[y]=min(c[y],x);
}
//先往右计算
for(int i=1;i<=c[1]-1;i++)
{
ans+=r[i]-1;
}
for(int i=c[1];i<=n;i++)
{
r[i]=1;
}
for(int i=1;i<=n;i++)
{
g[r[i]].push_back(i);
}
for(int i=1;i<=m;i++)
{
if(c[i]==1)
{
break;
}
ans+=T.ask(c[i]-1);
for(auto j:g[i])
{
T.add(j,1);
}
}
cout<<ans;

}