总结:
场上VP的时候一定要想清楚,再敲代码!!!
debug很搞心态的。
实际上这场整体来说较为简单。C题BFS,D题双指针,E题整除分块。
A. Comparing Two Long Integers
string a, b;
cin >> a >> b;
string aa, bb;
int len = a.length();
bool f = false;
for(int i = 0 ; i < len ; i ++)
{
if(f)
aa += a[i];
if(a[i] != '0' && !f)
f = true, aa += a[i];
}
len = b.length();
f = false;
for(int i = 0; i < len ; i ++)
{
if(f)
bb += b[i];
if(b[i] != '0' && !f)
f = true, bb += b[i];
}
int len1 = aa.length();
int len2 = bb.length();
if(len1 == len2)
{
int flog = 0;
for(int i = 0 ; i < len1 ; i ++)
{
if(aa[i] > bb[i])
{
flog = 1;
break;
}
else if(aa[i] < bb[i])
{
flog = -1;
break;
}
}
if(flog == 1) printf(">\n");
else if(flog == -1) printf("<\n");
else printf("=\n");
}
else if(len1 > len2)
{
printf(">\n");
}
else
{
printf("<\n");
}
B. Dinner with Emma
int main()
{
int n, m;
scanf("%d %d", &n, &m);
for(int i = 1 ; i <= n ; i ++)
h[i] = INF;
for(int i = 1 ; i <= n ; i ++)
{
for(int j = 1 ; j <= m ; j ++)
scanf("%d", &mm[i][j]), h[i] = min(h[i], mm[i][j]);
}
sort(h + 1, h + n + 1);
printf("%d\n", h[n]);
return 0;
}
C. The Labyrinth
题意:
给定n * m的矩阵,求每个*点能遇到多少白点。
思路:
非常明显可以预处理所有白点所在的连通块。然后对于每个*点,只要四个方向上遇到白点且互不在同一个连通块就可作为贡献。(不在同一连通块可对每个连通块进行标号)
在bfs搜四个方向的其他点时,要先检查坐标是否合法,因为 && 操纵从左到右进行的,一直到第一个不满足的时候才会结束,如果先判断是否为.那么坐标可能会出现负值,导致re。
code:
int dx[] = {-1, 0, 1, 0};
int dy[] = {0, 1, 0, -1};
int c[1010][1010];
int id[1010 * 1010];
void bfs(int x, int y, int cnt)
{
book[x][y] = true;
queue <note> alls;
alls.push({x, y, 1});
vector <PII> ALLS;
ALLS.push_back({x, y});
int ans = 1;
while(!alls.empty())
{
auto t = alls.front();
alls.pop();
for(int i = 0 ; i < 4 ; i ++)
{
int temp_x = t.x + dx[i];
int temp_y = t.y + dy[i];
if(temp_x >= 0 && temp_x < n && temp_y >= 0 && temp_y < m && !book[temp_x][temp_y] && mm[temp_x][temp_y] == '.' )
{
book[temp_x][temp_y] = true;
alls.push({temp_x, temp_y, t.w + 1});
ans ++;
ALLS.push_back({temp_x, temp_y});
}
}
}
for(auto t : ALLS)
c[t.first][t.second] = cnt;
id[cnt] = ans;
}
int main()
{
scanf("%d %d", &n, &m);
for(int i = 0 ; i < n ; i ++)
{
scanf("%s", mm[i]);
}
int cnt = 0;
for(int i = 0 ; i < n ; i ++)
{
for(int j = 0 ; j < m ; j ++)
{
if(mm[i][j] == '.' && !book[i][j])
{
bfs(i, j, ++ cnt);
}
}
}
for(int i = 0 ; i < n ; i ++)
{
for(int j = 0 ; j < m ; j ++)
{
if(mm[i][j] == '*')
{
c[i][j] = 1;
set <int> st;
for(int k = 0 ; k < 4 ; k ++)
{
int temp_x = i + dx[k];
int temp_y = j + dy[k];
if(temp_x >= 0 && temp_x < n && temp_y >= 0 && temp_y < m && mm[temp_x][temp_y] == '.')
{
st.insert(c[temp_x][temp_y]);
}
}
for(auto t : st)
c[i][j] += id[t];
}
}
}
for(int i = 0 ; i < n ; i ++)
{
for(int j = 0 ; j < m ; j ++)
{
if(mm[i][j] == '.')
cout << mm[i][j];
else printf("%d", c[i][j] % 10);
}
printf("\n");
}
return 0;
}
D. Longest k-Good Segment
题意:
找最长的一段区间包含<=k个不同的权值。
思路
明显的双指针。满足xx条件的最长区间问题
code:
int a[maxn], book[maxn];
int main()
{
int n, k;
scanf("%d %d", &n, &k);
for(int i = 1 ; i <= n ; i ++)
{
scanf("%d", &a[i]);
}
int res = 0, l = 0, r = 0;
for(int i = 1 , j = 1 , cnt = 0 ; i <= n ; i ++)
{
while(j <= n)
{
book[a[j]] ++;
if(book[a[j]] == 1)
{
if(cnt + 1 <= k)
{
cnt += 1, j ++;
}
else
{
book[a[j]] --;
break;
}
}
else j ++;
}
if(j - 1 - i + 1 > res)
res = j - 1 - i + 1, l = i, r = j - 1;
book[a[i]] --;
if(book[a[i]] == 0) cnt --;
}
printf("%d %d\n", l, r);
return 0;
}
E. Sum of Remainders
题意:
求 ∑ i = 1 m n m o d i \sum_{i = 1} ^ {m} n\; mod\; i ∑i=1mnmodi,其中n和m <= 1e13
思路:
直接暴力肯定不行。
考虑化简式子
非常经典的转换
n
m
o
d
i
=
n
−
⌊
n
/
i
⌋
∗
i
n\; mod \; i = n - \lfloor n / i \rfloor * i
nmodi=n−⌊n/i⌋∗i
那么原式变为
∑
i
=
1
m
n
−
⌊
n
/
i
⌋
∗
i
\sum_{i = 1} ^ {m} n - \lfloor n / i \rfloor * i
∑i=1mn−⌊n/i⌋∗i
进一步转化
n
∗
m
−
∑
i
=
1
m
⌊
n
/
i
⌋
∗
i
n * m - \sum_{i = 1} ^ {m}\lfloor n / i \rfloor * i
n∗m−∑i=1m⌊n/i⌋∗i
∑
i
=
1
m
⌊
n
/
i
⌋
\sum_{i = 1} ^ {m} \lfloor n / i \rfloor
∑i=1m⌊n/i⌋非常经典的整除分块问题
∑
i
=
1
m
⌊
n
/
i
⌋
∗
i
\sum_{i = 1} ^ {m} \lfloor n / i \rfloor * i
∑i=1m⌊n/i⌋∗i相当于在[l, r]区间上的一个等差数列求和。
code:
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int maxn = 1e5 + 10;
typedef pair <int, int> PII;
const ll mod = 1e9 + 7;
ll get_mod1(ll a, ll b)
{
return (a % mod + (b % mod)) % mod;
}
ll get_mod2(ll a, ll b)
{
return (a % mod * (b % mod)) % mod;
}
ll ksm(ll base, ll power)
{
ll res = 1;
while(power)
{
if(power & 1)
res = get_mod2(res, base);
base = get_mod2(base, base);
power >>= 1;
}
return res;
}
int main()
{
ll n, m;
scanf("%lld %lld", &n, &m);
ll res = get_mod2(n, m);
ll inv2 = ksm(2ll, mod - 2);
ll temp = 0;
for(ll l = 1, r ; l <= min(n, m) ; l = r + 1)
{
r = min(m , n / (n / l));
temp = get_mod1(temp, get_mod2(inv2, get_mod2(r - l + 1, get_mod2(n / l, l + r))));
}
printf("%lld\n",(res - temp + mod) % mod);
return 0;
}