(https://ac.nowcoder.com/acm/contest/3002/G)
我的思想:1,给出两个标记点first,last然后依次移动并将移动到位置的字母总数减一并维护ans。但是感觉不太好写就扔掉了。
2.暴力查找,结果超时了而且我太菜了想不出新方法了(困。。。)
结果一直交一直t,然后就放弃了。
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int MAX = 99999999;
char s[200010];
int main()
{
int n,m;
int sum;
int ans = MAX;
scanf("%d%d",&n,&m);
scanf("%s",s);
for(int i = 0;i < n;++i){
sum = 0;
for(int j = i;j < n;++j){
if(s[i] == s[j]){
sum++;
}
if(sum == m){
ans = min(ans,j - i + 1);
break;
}
}
}
printf("%d\n",ans == MAX ? -1 : ans);
}
感觉还是挺好的吧至少我造的样例过了。就是接近n^2的复杂度跑不了那么大的范围。
赛后看到几位大佬的(果然还是赛后共享代码更好)
摘录几位:
其一,用队列,代码如下:
参考id: xch233
#include <bits/stdc++.h>
using namespace std;
const int MAX = 0x3f3f3f3f;
string s;
int main()
{
int n,k;
int ans = MAX;
scanf("%d%d",&n,&k);
cin >> s;
for(int i = 0;i < 26;++i){
int cnt = 0;
queue<int> q;
for(int j = 0;j < n;++j){
if(s[j] - 'a'== i){
q.push(j);
cnt++;
if(cnt == k){
int tem = q.front();
q.pop();
cnt--;
ans = min(ans,j - tem + 1);
}
}
}
}
printf("%d\n",ans == MAX ? -1 : ans);
}
队列的性质很好的解决了我想的first和last标记的问题,不过我就是想不到啊。
其二,这个过于强大,瞻仰一下,比赛开始四分钟就做出来,真正的强者代码如下:
参考 id:wrjlinkkkkkk
#include <bits/stdc++.h>
using namespace std;
const int MAX = 0x3f3f3f3f;
const int maxn = 2e5+100;
int num[55];
int d[55][maxn];
char s[maxn];
int main()
{
int n,k;
int ans = MAX;
scanf("%d%d",&n,&k);
scanf("%s",s + 1);///可以将字符串首位从一开始
n = strlen(s + 1);
for(int i = 1;i <= n;++i){
int now = s[i] - 'a';
d[now][++num[now]] = i;///now记录字符,num记录字符数量整个d数组记录某字符出现的位置
}
for(int i = 0;i < 24;++i){
for(int j = 1;j + k - 1 <= num[i];++j){
ans = min(ans,d[i][j + k - 1] - d[i][j] + 1);///如果某字符出现次数超过或等于k
}
}
printf("%d\n",ans == MAX ? -1 : ans);
}
(https://ac.nowcoder.com/acm/contest/3002/A)
这个题吧,讲真我一直没搞懂我错在何处,规律我找的到是挺快的,样例也过了就是一直WA,搞得我心烦意乱。
错误代码:
#include <bits/stdc++.h>
using namespace std;
const int MAX = 1000000007;
int main()
{
long long n,m;
long long n1,m1;
scanf("%lld%lld",&n,&m);
long long ans = (2 * n * (n - 2) * (m - 1) % MAX+ 2 * m * (m - 2) * (n - 1) % MAX) % MAX;
if(n > 4) n1 = 2 * (n - 4) + 4;
else {
if(n == 2) n1 = 0;
if(n == 3) n1 = 2;
if(n == 4) n1 = 4;
}
if(m > 4) m1 = 2 * (m - 4) + 4;
else {
if(m == 2) m1 = 0;
if(m == 3) m1 = 2;
if(m == 4) m1 = 4;
}
ans += ((n - 1) * (n - 2) * m1 % MAX + (m - 1) * (m - 2) * n1 % MAX) % MAX;
ans = ans % MAX;
printf("%lld\n",ans);
}
我的大致想法和题解差不多,就是将面积为一的三角形分成两种情况:1.长是一的边和x或y轴平行。2.长是二的边和x或y轴平行。两种情况加起来就是总数。比赛时我看这个题交的人很多但正确率不甚高,估计好多像我一样样例过了但永远A不了的人。
正确代码:
#include <bits/stdc++.h>
using namespace std;
const int MAX = 1000000007;
int main()
{
long long n,m;
long long n1,m1;
long long ans;
scanf("%lld%lld",&n,&m);
n1 = (((m - 2) * (n - 1)) % MAX * (m + n - 2)) % MAX * 2;
m1 = (((n - 2) * (m - 1)) % MAX * (m + n - 2)) % MAX * 2;
ans = ((n1 % MAX) + (m1 % MAX)) % MAX;
printf("%lld\n",ans);
}
我在两个程序上都跑了一下极限情况即m = n = 1e9 - 1,我的程序结果是164378202,
正确答案是111999785,但是经过测验在100以内我的程序和正确答案结果是一致的
只能说明我的规律在较大数并不适用。还是我太菜了。