牛客寒假算法基础集训营1
文章目录
- 牛客寒假算法基础集训营1
- A [honoka和格点三角形](https://ac.nowcoder.com/acm/contest/3002/A)
- B [ kotori和bangdream](https://ac.nowcoder.com/acm/contest/3002/B)
- D [hanayo和米饭](https://ac.nowcoder.com/acm/contest/3002/D)
- E [ rin和快速迭代](https://ac.nowcoder.com/acm/contest/3002/E)
- G [ eli和字符串](https://ac.nowcoder.com/acm/contest/3002/G)
- H [ nozomi和字符串](https://ac.nowcoder.com/acm/contest/3002/H)
- I [nico和niconiconi](https://ac.nowcoder.com/acm/contest/3002/I)
题目链接:https://ac.nowcoder.com/acm/contest/3002?&headNav=www
A honoka和格点三角形
题意:给出一个n*m的矩阵,找出有如下条件的三角形的个数:
1.三角形的三个顶点均为格点,即横坐标和纵坐标均为整数。
2.三角形的面积为1
3.三角形至少有一条边和x轴或y轴平行。
思路:满足条件的三角形有两类:1、底为1,高为2;2、底为2,高为1。
使底边分别平行于x轴和y轴,其中会有重复的,计算中减去即可。
代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<queue>
#include<string>
#include<string.h>
using namespace std;
const int mod = 1e9 + 7;
int main()
{
long long n, m;
cin >> n >> m;
long long ans1, ans2, ans3, ans4;
ans1 = (2 * (n - 1) % mod * m % mod * (m - 2)) % mod;
ans2 = (2 * (m - 1) % mod * m % mod * (n - 2)) % mod;
ans3 = (2 * (m - 1) % mod * (n - 2) % mod * (n - 2)) % mod;
ans4 = (2 * (n - 1) % mod * (m - 2) % mod * (n - 2)) % mod;
cout << (ans1 + ans2 + ans3 + ans4) % mod << endl;
return 0;
}
B kotori和bangdream
签到题,根据概率算期望
代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<queue>
#include<string>
#include<string.h>
using namespace std;
int main()
{
double n,x,a,b;
scanf("%lf%lf%lf%lf",&n,&x,&a,&b);
double ans=n*(x/100)*a+n*(1-x/100)*b;
printf("%.2f\n",ans);
return 0;
}
D hanayo和米饭
签到题,标记数组,遍历找到未被标记的位置
代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<queue>
#include<string>
#include<string.h>
using namespace std;
int main()
{
int n,ans;
int arr[100005];
scanf("%d",&n);
memset(arr,0,sizeof(arr));
for(int i=0;i<n-1;i++){
int a;
scanf("%d",&a);
arr[a]=1;
}
for(int i=1;i<n+1;i++){
if(arr[i]==0){
ans=i;
break;
}
}
printf("%d\n",ans);
return 0;
}
E rin和快速迭代
题意:给出一个正整数X,求其因子数,令X等于其因子数,再求X因子数并X等于其因子数,不断迭代下去,最终X会等于2。求这个过程需要迭代多少次
思路:O( n \sqrt{n} n ) 求因子数 模拟过程
for循环中i开long long
代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<queue>
#include<string>
#include<string.h>
using namespace std;
const int mod = 1e9 + 7;
int main()
{
long long n;
cin >> n;
int ans = 0;
while(n != 2){
ans++;
int num = 0;
for(long long i = 1; i * i <= n; i++){
if(n % i == 0){
if(i * i == n) num++;
else num += 2;
}
}
n = num;
}
cout << ans << endl;
return 0;
}
G eli和字符串
题意:截取一段最短的连续字串,子串中至少包括K个相同的某个字母
思路:尺取法,,用map保存了尺取维护的区间中的字母的个数
代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<queue>
#include<string>
#include<string.h>
#include<map>
using namespace std;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int main()
{
int n, k;
string s;
cin >> n >> k;
cin >> s;
map <char, int> mp;
int L = 0, R = 0, ans = INF, sum = 0;
while(1){
while(R < n && sum < k){
mp[s[R]] += 1;
sum = max(sum, mp[s[R]]);
R += 1;
}
if(sum < k) break;
ans = min(R - L, ans);
mp[s[L]] -= 1;
if(s[L] == s[R - 1]) sum -= 1;
L += 1;
}
if(ans == INF) cout << -1 << endl;
else cout << ans <<endl;
return 0;
}
H nozomi和字符串
题意:一个 “01”串而言,每次操作可以把 0 字符改为 1 字符,或者把 1 字符改为 0 字符,最多可操作K次。在操作之后找出一个尽可能长的连续子串,这个子串上的所有字符都相同。
思路:K次操作,只能是全部将0变成1,或者全部将1变成0。全部将0变成1:先移动右端点,遇到0则将可操作次数-1(将0变为1,但不改变真值),如果可操作次数为0,就移动左端点,当左端点遇到0,可操作次数+1,重新循环。全部将1变成0,操作相同。两种可能都执行找出最大值。
代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<queue>
#include<string>
#include<string.h>
#include<map>
using namespace std;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int main()
{
int n, k;
string s;
cin >> n >> k;
cin >> s;
int L = 0, R = 0, num = 0, ans = 0;
//将0变为1
while(1){
while(R < n){
if(s[R] == '0' && num == k) break;
if(s[R] == '0' && num < k){
num++;
}
R++;
}
ans = max(R - L, ans);
if(R >= n) break;
while(s[L] != '0') L++;
num--;
L++;
}
//将1变为0
L = 0, R = 0, num = 0;
while(1){
while(R < n){
if(s[R] == '1' && num == k) break;
if(s[R] == '1' && num < k){
num++;
}
R++;
}
ans = max(R - L, ans);
if(R >= n) break;
while(s[L] != '1') L++;
num--;
L++;
}
cout << ans << endl;
return 0;
}
I nico和niconiconi
题意:给出一个长度为n字符串,“nico” 计a分,“niconi” 计b分,“niconiconi” 计c分。已被计数过的字符不能重复计数,找出最大的计数分数。
思路:线性DP
if (s.substr(i - 3, 4) == “nico”) dp[i]=max(dp[i],dp[i−4]+a)
if (s.substr(i - 5, 6) == “niconi”) dp[i]=max(dp[i],dp[i−6]+a)
if (s.substr(i - 9, 10) == “niconiconi”) dp[i]=max(dp[i],dp[i−10]+a)
代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<queue>
#include<string>
#include<string.h>
#include<map>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int e = 3e5 + 5;
ll dp[e];
int main()
{
ll n, a, b, c;
string s;
cin >> n >> a >> b >> c;
cin >> s;
dp[0] = 0;
for(int i = 1; i < n; i++){
dp[i] = dp[i - 1];
if(i >= 3 && s.substr(i - 3, 4) == "nico"){
dp[i] = max(dp[i], dp[i - 4] + a);
}
if(i >= 5 && s.substr(i - 5, 6) == "niconi"){
dp[i] = max(dp[i], dp[i - 6] + b);
}
if(i >= 9 && s.substr(i - 9, 10) == "niconiconi"){
dp[i] = max(dp[i], dp[i - 10] + c);
}
}
cout << dp[n - 1] << endl;
return 0;
}