天天快乐编程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";
	}
}
posted @ 2020-10-02 14:36  暴力都不会的蒟蒻  阅读(88)  评论(0编辑  收藏