前言:又到寒假了,依旧是被疫情困在家里的一天,还是希望自己不那么fw,和队长约了一块训练,div3开始,先练练手速,毕竟忙着期末考试得有半个月没怎么碰过键盘了,该账号开学前会持续更新每日训练题解,寒假目标:紫名。
题目链接
A-Points in Segments
题意:一个区间长为m,n 次询问,每次询问标记一段区间,问最后有多少区间没有标记。该题可参考校门外的树
题解:数据较小,暴力标记即可,时间复杂度O(nm),下面直接粘代码
bool book[110];
int32_t main()
{
int n, m, a, b, num = 0;
cin >> n >> m;
for(int i = 1; i <= n; i++)
{
cin >> a >> b;
for(int j = a; j <= b; j++)
book[j] = 1;
}
for(int i = 1; i <= m; i++)
if(book[i] == 0) num++;
cout << num << endl;
for(int i = 1; i <= m; i++)
{
if(book[i] == 0) cout << i << ' ';
}
return 0;
}
再粘一下差分的代码(O(max(n, m)))
int a[110], s[110];
int32_t main()
{
ICO;
int n, m, l, r, num = 0;
cin >> n >> m;
for(int i = 1; i <= n; i++)
{
cin >> l >> r;
a[l]++, a[r + 1]--;
}
for(int i = 1; i <= m; i++)
{
s[i] = s[i - 1] + a[i];
if(s[i] == 0) num++;
}
cout << num << endl;
for(int i = 1; i <= m; i++)
if(s[i] == 0) cout << i << ' ';
return 0;
}
B-Obtaining the String
题意:给你两个字符串s,t,移动s的字母(只能相邻之间移动),移动多少次可使s成为t(不要求最小移动步数),题目限制移动步数不得超过e4。
题解:很明显如果s如果能通过移动成为t,最大步数不会超过n^2,e4的限制就没有意义了,题目不要求最少步数,即可通过暴力向后匹配未匹配到的s[i],然后将匹配的字母交换到前面即可。
int a[30], b[30];
vector<int> res;
int32_t main()
{
ICO;
int n, book = 0;
string s, t;
cin >> n >> s >> t;
for(int i = 0; i < n; i++) //记录包含字母的个数
{
a[s[i] - 'a']++;
b[t[i] - 'a']++;
}
for(int i = 0; i < 26; i++) //若包含字母不同,肯定不能匹配
{
if(a[i] != b[i])
{
cout << -1;
return 0;
}
}
for(int i = 0; i < n; i++)
{
if(s[i] != t[i]) //遇到不匹配的字母
{
int j = i + 1;
while(s[j] != t[i]) j++; //两字符串所含字母相同,则一定可以找到匹配的字母
j--;
while(j >= i) //将匹配到的字母交换到前面,并记录交换路径
{
swap(s[j], s[j + 1]);
res.push_back(j + 1);
j--;
}
}
}
cout << res.size() << endl;
for(int i = 0; i < res.size(); i++)
cout << res[i] << ' ';
return 0;
}
C-Songs Compression
题意:有n个文件,内存限制为m。每个文件可压缩,现给你每个文件压缩前和压缩后的内存,要压缩一部分文件使所有的文件可以全部存储,求最少压缩文件的数量。
题解:用数组存储一下压缩文件的内存差,然后排序,从差值最大的开始压缩,直到可以全部存储,注意数据范围。
ll a[maxn], b[maxn], c[maxn];
int32_t main()
{
ICO;
ll n, m, res = 0;
cin >> n >> m;
for(int i = 1; i <= n; i++)
{
cin >> a[i] >> b[i];
c[i] = a[i] - b[i];
res += a[i];
}
sort(c + 1, c + 1 + n, greater<ll> ());
int num = 0;
for(int i = 1; i <= n; i++)
{
if(res <= m) break;
res -= c[i], num++;
}
if(res <= m) cout << num;
else cout << -1;
return 0;
}
D-Walking Between Houses
题意:有n个房子(编号1-n),你需要走k步然后走过的价值和为s,价值是你每走一步的起点和终点所在房间编号的差的绝对值,两步之间不能处于同一房子内(价值为0),所以一步的价值∈[1, n - 1],输出1-k步自己所在房间的编号。
题解:这题是这场比赛我被卡时间最长的,读完题发现题意清楚,思路也有,但是上手敲的时候发现其中有了诸多限制,比如你走i步就必须留下k - i的距离(要保证接下来的k - i步都有房子可走),最后所剩距离不够一趟的时候的处理方法等等。说一下思路,在你保留k - i的时候,若所剩距离大于n - 1,则可以一步从头到尾(从尾到头),否则就走完该步可走的,最后的k - i步每步走1就好。
int32_t main()
{
ICO;
ll n, k, s;
cin >> n >> k >> s;
if((n - 1) * k < s || k > s) cout << "NO" << endl;
else
{
cout << "YES" << endl;
ll p, sum = 0, now = 1;
bool ok = 1;
for(int i = 1; i <= k; i++)
{
p = (s - sum) - (k - i); //p为当前可走价值 sum为已走价值
if(p == 1) //最后k - i步,每步走1,注意转头
{
int j = i;
while(j <= k)
{
while(j <= k && (++now) <= n)
{
cout << now << ' ';
j++;
}
now--;
while(j <= k && (--now) >= 1)
{
cout << now << ' ';
j++;
}
now++;
}
break;
}
if(p >= n) //可走价值大于一步最大价值时头尾跳即可
{
if(ok) now = n;
else now = 1;
p = n - 1;
ok = !ok;
}
else
{
if(ok) now = 1 + p;
else now = n - p;
}
sum += p;
cout << now << ' ';
}
}
return 0;
}
E-Stars Drawing
题意:判断所给矩阵是否可以拆成几个单独的星星,原矩阵的‘*’可被拆成的星星共用,即被拆成的完整的星星的并集等于原矩阵。
题解:使用二维差分,对所拆的星星进行覆盖,看覆盖后的图案和原矩阵是否匹配。
const int maxn = 1e3 + 2;
char ch[maxn][maxn];
int l[maxn][maxn], r[maxn][maxn], up[maxn][maxn], down[maxn][maxn], res1[maxn][maxn], res2[maxn][maxn];
int res[maxn][maxn];
vector<pair<pair<int, int>, int> > v;
int32_t main()
{
ICO;
int n, m;
cin >> n >> m;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
cin >> ch[i][j];
if(ch[i][j] == '*')
{
if(ch[i][j - 1] == '*') l[i][j] = l[i][j - 1] + 1;
if(ch[i - 1][j] == '*') up[i][j] = up[i - 1][j] + 1;
}
}
}
for(int i = n; i >= 1;i--)
{
for(int j = m; j >= 1; j--)
{
if(ch[i][j] == '*')
{
if(ch[i + 1][j] == '*') down[i][j] = down[i + 1][j] + 1;
if(ch[i][j + 1] == '*') r[i][j] = r[i][j + 1] + 1;
}
}
}
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
int minn = min(min(l[i][j], up[i][j]), min(r[i][j], down[i][j]));
if(minn)
{
pair<int, int> l;
pair<pair<int, int>, int> q;
l.first = i, l.second = j;
q.first = l, q.second = minn;
v.push_back(q);
res1[i][j - minn]++, res1[i][j + minn + 1]--;
res2[j][i - minn]++, res2[j][i + minn + 1]--;
}
}
}
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
res1[i][j] += res1[i][j - 1];
for(int i = 1; i <= m; i++)
for(int j = 1; j <= n; j++)
res2[i][j] += res2[i][j - 1];
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
res[i][j] = res1[i][j] + res2[j][i];
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
if(ch[i][j] == '*' && res[i][j] == 0)
{
cout << -1 << endl;
return 0;
}
}
}
int l = v.size();
cout << l << endl;
for(int i = 0; i < l; i++)
cout << v[i].first.first << ' ' << v[i].first.second << ' ' << v[i].second << endl;
return 0;
}
总结:长时间不敲代码确实会生疏很多,D题当时被卡了太久,期待在以后的学习中提高自己。