文章目录
感想
刚开始遇到了一阵诡异的网络问题,还有个挺无法理解的东西(下面的B题),很微妙。
A. Garland
1.题目内容
2.个人思路
比较直白,四个相同就是-1,三个就是6次,一和二就是四次。
3.代码
ll t, n, m, p = 1000000007, k;
ll dp[300005][2];
map<char, int> ci;
string s;
int main() {
cin >> t;
while (t--) {
cin >> s;
ci.clear();
for (int i = 0; i <= s.size(); i++) {
ci[s[i]]++;
}
int ma = 0;
for (auto x : ci) {
ma = max(ma, x.second);
}
if (ma == 1) {
cout << "4\n";
}
if (ma == 2) {
cout << "4\n";
}
if (ma == 3) {
cout << "6\n";
}
if (ma == 4) {
cout << "-1\n";
}
}
return 0;
}
B. Points on Plane
1.题目内容
2.个人思路
可以画个图看一下,代价为0的只有一个,为1的有4个,为2的有8个…以此类推。然后任意两个点距离不能小于等于1,最佳情况一定就是每隔 \sqrt (2) 个距离去取点,然后就会发现实际上就是只能取代价差为2的点,也就是
0 2 4 …
1 3 5 …
这个规律取点。
然后发现这些求和正好是最大数字+1的平方,接下来只要对输入的n开方找数就可以了。
这个题我最早写的 != ,结果过不去,我琢磨了半天改成 < ,过了,也许跟自带的sqrt运算有关系吧,很迷惑。
3.代码
ll t, n, m, p = 1000000007, k;
ll dp[300005][2];
map<char, int> ci;
string s;
int main() {
cin >> t;
while (t--) {
cin >> n;
ll x = sqrt(n);
if (x * x < n) {
cout << x << "\n";
}
else {
cout << x - 1 << "\n";
}
}
return 0;
}
C. Sum on Subarrays
1.题目内容
2.个人思路
思路其实很灵活的一个题,我看我周围的代码写成什么样的都有。
我个人的思路是左侧为正数,右侧为负数,直接为-1000,正数的子数组和肯定是正数,假设有x个正数
k的范围应该是(x)(x - 1) / 2 ~ (x)(x - 1) / 2 + x + 1
如果是不止(x)(x - 1) / 2的情况,就需要将第一个负数变小,小到与前面(k-(x)(x - 1) / 2)个子数组求和是正数即可,我这里设置成了正数是2,负数是-1000
,需要变化的负数是 -1 - (x+1-k+(x)(x - 1) / 2) * 2;
3.代码
ll t, n, m, p = 1000000007, k;
ll dp[300005][2];
map<char, int> ci;
string s;
int main() {
cin >> t;
while (t--) {
cin >> n >> k;
vector<int> ans;
for (int i = 0; i < n; i++) {
ans.push_back(-1000);
}
int now = 0;
for (int i = 0; i < n; i++) {
now += (i + 1);
if (now <= k) {
ans[i] = 2;
}
if (now < k && now + i + 2 > k) {
ans[i + 1] = -1 - (i + 1 - k + now) * 2;
}
}
for (int i = 0; i < ans.size(); i++) {
cout << ans[i] << " ";
}
cout << "\n";
}
return 0;
}
D. Binary String Sorting
1.题目内容
2.个人思路
其实就是dp,假设dp[i]是1~i有序情况下的最小消耗,cnt[i]为当前最小消耗下的1的数量,pos[i]是在s中到i时的1的总个数,此时就是有三种可能的方案。
交换代价以下称为c1,删除代价称为c2.
如果当前位置是0并且有大于0个1
- 把出现过的的1都删除掉,代价就是pos[i] * c2,cnt清空。
- 把这个0删除掉,代价就是dp[i - 1] + c2,cnt保持不变。
- 把0移动到1之前,代价是dp[i - 1] + cnt[i - 1] * c1,cnt保持不变。
如果当前位置是1,dp[i] = dp[i - 1],cnt[i] = cnt[i-1] + 1。
三个取最小即可。
如果出现相等(大概不会有)的情况,优先选择清空。
最后输出dp[n]即可。
3.代码
ll t, n, m, p = 1000000007, k;
ll c1 = 1e12, c2 = 1e12 + 1;
ll dp[300005], cnt[300005], pos[300005];
string s;
int main() {
cin >> t;
while (t--) {
cin >> s;
for (int i = 0; i < s.size(); i++) {
cnt[i] = 0;
dp[i] = 1e18;
pos[i] = 0;
}
for (int i = 0; i < s.size(); i++) {
if (s[i] == '1') pos[i]++;
if (i > 0) pos[i] += pos[i - 1];
}
dp[0] = 0;
for (int i = 0; i < s.size(); i++) {
if (i > 0 && s[i] == '0') {
if (cnt[i - 1] > 0) {
ll xx = pos[i] * c2;
ll yy = dp[i - 1] + cnt[i - 1] * c1;
ll zz = dp[i - 1] + c2;
if (xx <= yy && xx <= zz) {
dp[i] = xx;
cnt[i] = 0;
}
else if(yy < zz && yy < xx) {
dp[i] = yy;
cnt[i] = cnt[i - 1];
}
else {
dp[i] = zz;
cnt[i] = cnt[i - 1];
}
}
else if (cnt[i] == 0) {
dp[i] = dp[i - 1];
}
}
else {
if (i == 0 && s[i] == '1') cnt[i] = 1;
else if (i > 0) {
cnt[i] = cnt[i - 1] + 1;
dp[i] = dp[i - 1];
}
}
}
cout << dp[s.size() - 1] << "\n";
}
return 0;
}
总结
后面写到E发现就过了70个人,直接睡觉去了(电脑没电了),属于是我不配的领域了,对不起。