比赛链接:
SDNU ACM-ICPC 2019 Training Weekly Contest 1
题目链接:
A - Concatenated Multiples
题目大意:
给 n 个数,将这 n 个数两两组合,问有多少组可以被 k 整除.
分析:
比如 a 与 b 组合,则组合后为 .
所以想要被整除只需要 ( % k + b % k) % k == 0.
所以用 map[i][j] 来表示 % k 后余数为 j 的数的次数.
之后 ans += 每个数对应前缀数 % k 的次数.
注意要特判一下 a 与 a 连接后的数是否为 k 的倍数.
代码实现:
#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <vector>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define eps 1e-4
#define PI acos(-1.0)
#define ll long long int
using namespace std;
int a[(int)1e5 * 2 + 10];
map <int, ll> mp[15];
int main()
{
int n, k;
scanf("%d %d", &n, &k);
for(int i = 0; i < n; ++i)
{
scanf("%d", &a[i]);
ll x = a[i];
for(int j = 1; j <= 10; ++j)
{
x *= 10;
x %= k;
mp[j][x]++;
}
}
ll ans = 0;
for(int i = 0; i < n; ++i)
{
ll x = a[i] % k;
int len = log10(a[i]) + 1;
ans += mp[len][(k - x % k) % k];
for(int j = 0; j < len; ++j)
x = x * 10 % k;
if((x + a[i] % k) % k == 0)
ans--;
}
printf("%lld\n", ans);
return 0;
}
题目链接:
B - Creating the Contest
题目大意:
给 n 个数字,呈递增序列,现让你确定满足连续且 子序列的最大长度.
分析:
贪心,遇到不满足条件的断开即可,取最大长度.
代码实现:
#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <vector>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define eps 1e-4
#define PI acos(-1.0)
#define ll long long int
using namespace std;
ll a[(int)1e5 * 2 + 10];
int main()
{
int n;
scanf("%d", &n);
for(int i = 0; i < n; ++i)
scanf("%lld", &a[i]);
int ans = 1;
int cnt = 1;
for(int i = 1; i < n; ++i)
{
if(a[i - 1] * 2 >= a[i])
cnt++;
else
cnt = 1;
ans = max(ans, cnt);
}
printf("%d\n", ans);
return 0;
}
题目链接:
C - Inventory
题目大意:
给 n 个数,输出一个新的排列,用最少次数的替换使新排列的数为 1 ~ n 的排列(顺序不固定).
分析:
水题,直接做.
代码实现:
#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <vector>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define eps 1e-4
#define PI acos(-1.0)
#define ll long long int
using namespace std;
const int M = (int)1e5 + 10;
int a[M];
bool vis[M];
int main()
{
int n;
scanf("%d", &n);
for(int i = 0; i < n; ++i)
{
scanf("%d", &a[i]);
if(a[i] <= n)
vis[a[i]] = 1;
}
queue <int> q;
for(int i = 1; i <= n; ++i)
{
if(!vis[i])
q.push(i);
}
for(int i = 0; i < n; ++i)
{
if(vis[a[i]])
{
vis[a[i]] = 0;
continue;
}
a[i] = q.front();
q.pop();
}
for(int i = 0; i < n; ++i)
printf("%d%c", a[i], i == n - 1 ? '\n' : ' ');
return 0;
}
题目链接:
D - Many Equal Substrings
题目大意:
给定一个字符串, 以最小长度拼接 k 次,要求输出拼接后的字符串.
分析:
n 最大才 50,直接暴力求重合长度再相应输出即可.
代码实现:
#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <vector>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define eps 1e-4
#define PI acos(-1.0)
#define ll long long int
using namespace std;
string s;
int f()
{
int len = s.size();
for(int i = 1; i < len; ++i)
{
if(s.substr(i) == s.substr(0, len - i))
return len - i;
}
return 0;
}
int main()
{
int n, k;
scanf("%d %d", &n, &k);
cin >> s;
int len = f();
cout << s;
for(int i = 1; i < k; ++i)
cout << s.substr(len);
cout << "\n";
return 0;
}
题目链接:
E - Maximal Intersection
题目大意:
给定 n 个区间,现让你移走一个区间,求剩余区间交集的最大值.
分析:
用两个 multiset 分别存左右区间端点,然后枚举移走的区间.
代码实现:
#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <vector>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define eps 1e-4
#define PI acos(-1.0)
#define ll long long int
using namespace std;
struct node
{
int l;
int r;
};
struct node s[(int)1e5 * 3 + 10];
multiset <int> l, r;
int main()
{
int n;
scanf("%d", &n);
for(int i = 0; i < n; ++i)
{
scanf("%d %d", &s[i].l, &s[i].r);
l.insert(s[i].l);
r.insert(s[i].r);
}
int ans = 0;
for(int i = 0; i < n; ++i)
{
l.erase(l.find(s[i].l));
r.erase(r.find(s[i].r));
ans = max(ans, *r.begin() - *l.rbegin());
l.insert(s[i].l);
r.insert(s[i].r);
}
printf("%d\n", ans);
return 0;
}
题目链接:
F - Multicolored Markers
题目大意:
有 a 个红格子,b 个蓝格子,要求用这 a + b 个格子围成一个矩形,且至少有一种颜色的格子为矩形.
求大矩形周长的最小值.
分析:
枚举大矩形最短的边,再检查是否可行.
代码实现:
#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <vector>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define eps 1e-4
#define PI acos(-1.0)
#define ll long long int
using namespace std;
bool check(ll a, ll b, ll x, ll y)
{
for(ll i = x; i >= 1; --i)
{
if(a % i == 0 && a / i <= y)
return 1;
if(b % i == 0 && b / i <= y)
return 1;
}
return 0;
}
int main()
{
ll a, b;
scanf("%lld %lld", &a, &b);
ll sum = a + b;
ll ans = 2 * (a + b) + 10;
for(ll i = 1; i * i <= sum; ++i)
{
if(sum % i)
continue;
ll x = i;
ll y = sum / x;
if(check(a, b, x, y))
ans = min(ans, 2 * (x + y));
}
printf("%lld\n", ans);
return 0;
}
题目链接:
G - Music
题目大意:
给定 T,S,q,求这首歌播放的次数.
T:音乐的总时长
S:预先下载好的时长
q:q 秒钟能够下载 q - 1 秒的音乐
分析:
追击相遇问题.
设在 t 时刻,音乐播放到未下载的部分.
则
解得 t == sq.
然后重复这个过程直到音乐全部播放完.
代码实现:
#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <vector>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define eps 1e-4
#define PI acos(-1.0)
#define ll long long int
using namespace std;
int main()
{
int T, s, q;
scanf("%d %d %d", &T, &s, &q);
int t = 1;
int cnt = 1;
while(1)
{
t = s * q;
s = t;
if(t >= T)
{
printf("%d\n", cnt);
break;
}
cnt++;
}
return 0;
}
题目链接:
H - Primes or Palindromes?
题目大意:
:不大于 n 素数的个数.
rub(n) :不大于 n 回文数的个数(这里规定 0 不是回文数,由于没看清一直在 WA ).
给定整数 p 和 q,求满足 这个式子的 n 的最大值.
分析:
通过线性筛易得.
回文数一开始用 stringstream 结果超时,后来才发现直接暴力就可以.
最后枚举 n 就可以.
注意最后要加上 long long.
代码实现:
#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <vector>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define eps 1e-4
#define PI acos(-1.0)
#define ll long long int
using namespace std;
const int M = (int)1e7 + 10;
int prime[M];
bool vis[M];
int num1[M];
int num2[M];
void init1()
{
int len = 0;
for(int i = 2; i < M; ++i)
{
if(!vis[i])
prime[len++] = i;
for(int j = 0; j < len && i * prime[j] < M; ++j)
{
vis[i * prime[j]] = 1;
if(i % prime[j] == 0)
break;
}
}
for(int i = 2; i < M; ++i)
num1[i] = num1[i - 1] + !vis[i];
}
bool is(int n)
{
int m = n;
int sum = 0;
while(m)
{
sum *= 10;
sum += m % 10;
m /= 10;
}
return sum == n;
}
void init2()
{
for(int i = 1; i < M; ++i)
num2[i] = num2[i - 1] + is(i);
}
int main()
{
init1();
init2();
int p, q;
scanf("%d %d", &p, &q);
for(int i = M - 1; i >= 0; --i)
{
if((ll)num2[i] * p >= (ll)num1[i] * q)
{
printf("%d\n", i);
break;
}
}
return 0;
}
题目链接:
J - Tree with Small Distances
题目大意:
有一棵树,可以连接相应节点,要求每个节点与第 1 个节点的距离小于等于 2,求最少连线数.
分析:
贪心,如果 dis[i] > 2 的话,肯定是连接 father[i] 更实惠.
其实就是个无向图图,直接存.
然后 dfs 求每个节点的 dis,这时要特判一下 t 的子节点不能为 t 的父节点.
随后将 dis > 2 的节点存到优先队列里(方便按 dis 排序)
接着更新就可以了,记得要把第 i 个节点的周围节点都更新.
代码实现:
#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <vector>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define eps 1e-4
#define PI acos(-1.0)
#define ll long long int
using namespace std;
const int M = (int)1e5 * 2 + 10;
vector <int> v[M];
int father[M];
int dis[M];
bool vis[M];
struct node
{
int num;
int len;
};
bool operator < (node a, node b)
{
return a.len < b.len;
}
void dfs(int now, int fa)
{
int len = v[now].size();
for(int i = 0; i < len; ++i)
{
int t = v[now][i];
if(t == fa)
continue;
dis[t] = dis[now] + 1;
father[t] = now;
dfs(t, now);
}
}
int main()
{
int n;
scanf("%d", &n);
for(int i = 1; i < n; ++i)
{
int a, b;
scanf("%d %d", &a, &b);
v[a].push_back(b);
v[b].push_back(a);
}
dfs(1, 0);
priority_queue <node> q;
for(int i = 1; i <= n; ++i)
{
if(dis[i] > 2)
{
struct node t;
t.num = i;
t.len = dis[i];
q.push(t);
}
}
int ans = 0;
while(!q.empty())
{
int t = q.top().num;
q.pop();
if(vis[t])
continue;
int u = father[t];
vis[u] = 1;
ans++;
int len = v[u].size();
for(int i = 0; i < len; ++i)
vis[v[u][i]] = 1;
}
printf("%d\n", ans);
return 0;
}