天天快乐编程2020年OI集训队 训练5题解
本次训练内容为STL、数论和基本数据结构。
1.4862: 接水问题
NOIP2010普及组T2
在m个水龙头里选最小的值,这就是下一个(可能有多个)接完水的同学。然后让下一个接水的同学补上这个位置。
当然,我们每次不一定要把所有接完水的同学都记录下来,我们可以假设这个同学接完水后,下一个接完水的同学在0秒后接完水。
#include <bits/stdc++.h>
using namespace std;
int n, m, ans, w[105];
int main()
{
cin>>n>>m;
for (int i = 0; i < m; i++)
{
cin>>w[i];
if (ans < w[i])
ans = w[i];
}
int minn, t;
for (int i = m; i < n; i++)
{
//记录最小的下标位置
minn = 0;
for (int i = 1; i < m; i++)
if (w[minn] > w[i])
{
minn = i; //记录位置
}
cin>>t;
w[minn] += t;
//更新答案
if (ans < w[minn])ans = w[minn];
}
cout<<ans;
return 0;
}
每次枚举最小值太烦了,也可以直接用STL的优先队列(堆)来完成,速度也快。scanf/printf语句比cin/cout也会更快一点,如果可以手写堆是坠好的~
#include <bits/stdc++.h>
using namespace std;
//小顶堆要重载运算符
priority_queue<int, vector<int>, greater<int>> pq;
int n, m, ans;
int main()
{
scanf("%d%d", &n, &m);
int w, t;
for (int i = 0; i < m; i++)
{
scanf("%d", &w);
if (ans < w)
ans = w;
pq.push(w);
}
for (int i = m; i < n; i++)
{
scanf("%d", &w);
t = pq.top() + w;
if (ans < t)
ans = t;
pq.pop();
pq.push(t);
}
printf("%d\n", ans);
return 0;
}
wch的暴力模拟
#include<bits/stdc++.h>
using namespace std;
int n, m, t=0;
int w[10005];
bool find()
{
int flag=1;
for(int i=0;i<m;i++)
{
if(w[i]!=0)
flag=0;
}
if(flag==1)return false;
if(flag==0)return true;
}
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)cin>>w[i];
int j=m;
while(find())
{
for(int i=0;i<m;i++)
{
if(w[i]>0)
w[i]--;
if(w[i]==0 && j<n)
{
swap(w[i],w[j]);
j++;
}
}
t++;
}
cout<<t<<"\n";
return 0;
}
2.4865: 统计单词数
NOIP2011普及组T2
可以直接用string的find函数进行统计,首尾都加上空格
#include <bits/stdc++.h>
using namespace std;
int main()
{
//定义两个字符串
string a, b;
//使用getline读入一行
getline(cin, a);
getline(cin, b);
//转换大小写,可以都转换为大写或小写
for (int i = 0; i < a.length(); ++i)
{
a[i] = tolower(a[i]);
}
for (int i = 0; i < b.length(); ++i)
{
b[i] = tolower(b[i]);
}
//因为连起来的不算,所以要在前后加几个空格,一定要是同样多的,同量减同量,等于同量
a = ' ' + a + ' ';
b = ' ' + b + ' ';
//先看看会不会找不到,可以使用find函数
if (b.find(a) == string::npos)
{
cout << -1 << "\n";
}
else
{
//如果找得到,记录下初始位置
int ans = b.find(a),t = b.find(a), s = 0;
while (t != string::npos)
{
//不断继续向下找
t = b.find(a, t + 1);
s++;
}
//输出总共有几个和第一个的位置
cout << s << " " << ans << endl;
}
return 0;
}
直接模拟,进行字符串的全匹配也可以
#include <bits/stdc++.h>
using namespace std;
//数组必须够大
char a[15], b[1000005];
int main()
{
gets(a + 1);
gets(b + 1);
a[0] = b[0] = ' ';
//在ab均加空格,以空格做为结束
strcat(a, " ");
strcat(b, " ");
//全部转换为大写,小写字母ASCII大,直接>='a'也可以
for (int i = 0; a[i]; i++)
{
if (a[i] >= 'a')
a[i] -= 'a' - 'A';
}
for (int i = 0; b[i]; i++)
{
if (b[i] >= 'a')
b[i] -= 'a' - 'A';
}
int ans = -1, s = 0, l = strlen(a);
for (int i = 0; b[i]; i++)
{
if (b[i] == ' ')
{
int j = 0;
for (; j < l && i - j >= 0; j++)
{
if (b[i - j] != a[l - j - 1])
{
break;
}
}
//l的长度全部一样
if (j == l)
{
s++;
if (ans == -1)
{
ans = i - l + 1;
}
}
}
}
if (ans == -1)
{
printf("-1");
}
else
{
printf("%d %d", s, ans);
}
return 0;
}
3.4867: 表达式的值
NOIP2011普及组T4
T4一般情况下是最难的。
这个题目要 dp(or递推)+栈模拟
对于一道表达式求值的题,可通过判断运算符的优先级进行栈模拟
而这道题,还需要在模拟过程中利用乘法原理计算一下方案数
怎么dp(或者怎么递推)
设运算符左边为x,右边为y,运算结果为f
当运算符为 + 时:
f(0)=x(0) * y(0)
f(1)=x(0) * y(1) + x(1) * y(0) + x(1) * y(1)
当运算符为 * 时:
f(1) = x(1) * y(1)
f(0) = x(0) * y(0) + x(0) * y(1) + x(1) * y(0)
判断空位
右括号')'后无空位,其他运算符后都有一个空位
对于运算符的处理
对于左括号'(' 直接压入栈中即可
''的优先级比'+'高
当运算符为''时,将之前的运算计算出再将''入栈
当运算符为'+'时,将之前的''运算先计算出结果后再将'+'入栈
对于右括号')',直到遇见左括号'('前都要计算,左括号'('出栈,右括号')'入栈
#include <bits/stdc++.h>
using namespace std;
struct dp
{
int zero, one;
} ans[150001];
int len, t = 1;
const int MD = 10007;
string str;
stack<char> s;
inline void dispose(char ch, dp &a, dp &b)
{
if (ch == '+')
{
a.one = (a.one * (b.zero + b.one) + a.zero * b.one) % MD;
a.zero = a.zero * b.zero % MD;
}
else
{
a.zero = (a.zero * (b.zero + b.one) + a.one * b.zero) % MD;
a.one = a.one * b.one % MD;
}
}
int main()
{
cin >> len >> str;
str += ')';
ans[1].zero = ans[1].one = 1;
s.push('(');
for (int i = 0; i <= len; i++)
if (str[i] == '(')
s.push('(');
else if (str[i] == ')')
{
for (; s.top() != '('; s.pop(), t--)
dispose(s.top(), ans[t - 1], ans[t]);
s.pop();
}
else
{
for (; s.top() <= str[i] && s.top() != '('; s.pop(), t--)
dispose(s.top(), ans[t - 1], ans[t]);
s.push(str[i]);
ans[++t].zero = 1;
ans[t].one = 1;
}
cout << ans[1].zero;
return 0;
}
本题也可以用笛卡尔树去做。
4.4860: 细胞分裂
NOIP2011普及组T3
分解质因数就能解决这个题目了
首先看细胞的质因数是不是包含了容器的所有质因数,如果没有,那么就不能放入容器中
如果全部包含,那么最终值就是质因数次数之差的最大值+1。
#include <bits/stdc++.h>
using namespace std;
int n, m1, m2, a[10005], b[10005], ma, t = 2, c, ans = 0x3f3f3f3f, l;
int main()
{
cin >> n >> m1 >> m2;
for (int i = 1; i <= n; i++)
cin >> a[i];
if (m1 == 1)
{
cout << 0 << endl;
return 0;
}
//分解质因数
while (m1 != 1)
{
while (m1 % t == 0)
m1 /= t, b[t]++;
ma = max(ma, t);
//要乘上m2
b[t++] *= m2;
}
for (int i = 1; i <= n; i++)
{
l = 0;
for (int j = 2; j <= ma; j++)
{
if (!b[j])
continue;
c = 0;
while (!(a[i] % j))
a[i] /= j, c++;
if (!c)
{
l = 0x3f3f3f3f;
break;
}
//算次数差
l = max(l, (b[j] - 1) / c);
}
ans = min(ans, l);
}
cout << (ans == 0x3f3f3f3f ? -1 : ans + 1) << "\n";
return 0;
}
5.4813: 机器翻译
NOIP2010提高组T1
清空最早进入内存的那个单词,那就是先进先出,我们可以用队列进行模拟
#include <bits/stdc++.h>
using namespace std;
//队列模拟内存情况
queue<int> q;
int m,n,ans;
//判断单词是否在内存中
bool inq[1010];
int main()
{
cin>>m>>n;
for(int i=1;i<=n;i++)
{
int x;
cin>>x;
//能够在内存中查找就跳过
if(inq[x])continue;
else
{
//如果内存满了,最早进入内存的那个单词出列
if(q.size()>=m)
{
inq[q.front()]=false;
q.pop();
}
//把外存的结果加入内存以便下次查找
q.push(x);
inq[x]=true;
ans++;
}
}
cout<<ans;
return 0;
}
6.4781: 一元三次方程求解
NOIP2001提高组T1
本来我也以为是个数学题,需要用数学求解,但是题目根的范围在-100至100之间,我们枚举答案就可以了
#include<bits/stdc++.h>
using namespace std;
double a,b,c,d;
int main()
{
int m=0;
cin>>a>>b>>c>>d;
for(double x=-100.0; x<=100.0; x+=0.01)
{
//浮点数的比较特殊,因为double是不精确的
if(fabs(a*x*x*x+b*x*x+c*x+d)<=0.000001)
{
if(m)printf(" ");
printf("%.2f",x),m=1;
}
}
return 0;
}
7.4810: Hankson的趣味题
NOIP2009提高组T1
对于给定的a0,a1,b0和b1,使得GCD(X,a0)=a1,且LCM(X,b0)=b1
数据保证
a0能被a1整除,b0能被b0整除
我们只要找所有b1的因数,一个个check即可 时间复杂度O(nsqrt(b1)log1e7)
#include<bits/stdc++.h>
using namespace std;
long long lcm(int a,int b)
{
return 1LL*a/__gcd(a,b)*b;
}
int T,a0,b0,a1,b1;
int gao()
{
int ans=0;
int t=sqrt(b1+0.5);
for(int i=1;i<=t;i++)
if(b1%i==0)
{
if(lcm(i,b0)==b1&&__gcd(i,a0)==a1)ans++;
if(b1!=i*i)
if(lcm(b1/i,b0)==b1&&__gcd(b1/i,a0)==a1)
ans++;
}
return ans;
}
int main()
{
cin>>T;
while(T--)
{
cin>>a0>>a1>>b0>>b1;
cout<<gao()<<"\n";
}
}
本文来自博客园,作者:暴力都不会的蒟蒻,转载请注明原文链接:https://www.cnblogs.com/BobHuang/p/13761416.html