zoukankan      html  css  js  c++  java
  • 天天快乐编程2020年OI集训队 训练11题解

    上次发现大家对简单题还是掌握不牢固,这次还是一些简单题,也就是比赛中第一第二题给你们练练。大家如果不是很忙的话注意一下赛后的补题,即使你是入门级的同学,提高级的题目也是可以尝试的。

    1.6019: 金币

    NOIP2015 普及组T1
    这个题目k仅有10,000,比较小,可以直接一重循环

    #include <bits/stdc++.h>
    using namespace std;
    int main()
    {
    	int i, n, x = 1, t = 1, sum = 0;
    	scanf("%d", &n);
    	for (i = 1; i <= n; i++)
    	{
    		sum += t;
    		//到x了,下次要多一个币
    		if (i == x)
    		{
    			t++;
    			x += t;
    		}
    	}
    	printf("%d
    ", sum);
    	return 0;
    }
    

    模拟的方法有麻烦的,有简单的,建议写简单的方法
    这个题目存在一个通项公式的写法吗,前面是在进行平方和,平方和有公式的,那成了

    [1^2+2^2...+n^2=n(n+1)(2n+1)/6\ 1+2+3+...+n=n(n+1)/2 ]

    如果过了以k金币为结束的n天,那么就有一条方程
    n * (n+1)=2 * k。即k=(sqrt(1+8 * n)-1)/2

    #include <bits/stdc++.h>
    using namespace std;
    int main()
    {
    	int n;
    	cin >> n;
    	int k = (sqrt(1 + 8 * n + 0.5) - 1) / 2;
    	int sum = (k * (k + 1) * (2 * k + 1)) / 6;
    	//求出剩下的部分
    	n -= k * (k + 1) / 2;
    	sum += n * (k + 1);
    	cout << sum;
    	return 0;
    }
    

    2.5991: 成绩

    NOIP2017 普及组T1
    就这样一个简单题,当时也是有人没做对,OI赛制提交了不能实时得到结果,解题时一定要小心谨慎

    #include <bits/stdc++.h>
    using namespace std;
    int main()
    {
    	int a, b, c;
    	cin >> a >> b >> c;
    	printf("%.f", a * 0.2 + b * 0.3 + c * 0.5);
    }
    

    3.4843: 花生采摘

    NOIP2004普及组T2
    这也是个模拟题,需要注意没有两株花生株的花生数目相同
    我们想要采摘到最多的花生数直接从最大的开始采摘即可,然后每次时间够就去摘,求的是曼哈顿距离

    #include <bits/stdc++.h>
    using namespace std;
    
    struct T
    {
    	//用结构体存坐标和数量及时间。
    	int x, y, time, w;
    } a[405];
    int cmp(T a,T b)
    {
    	return a.w>b.w;
    }
    int main()
    {
    	int m, n, t;
    	cin >> m >> n >> t;
    	//记录有花生的个数
    	int tot = 0;
    	for (int i = 0; i < m; i++)
    		for (int j = 0, x; j < n; j++)
    		{
    			cin >> x;
    			if (x > 0)
    			{
    				//下面有花生的时候就存储,记得下标从1开始
    				a[tot++] = {i+1,j+1,0,x};
    			}
    		}
    	//从大到小排序
    	sort(a,a+tot,cmp);
    	int ans=0;
    	//枚举每个花生
    	for (int i = 0; i < tot; i++)
    	{		  
    		if (i == 0)
    		{
    			//第一个花生多多一开始可以跳到第一个最多花生的所在列。
    			a[i].time = a[i].x + 1;
    		}
    		else
    		{
    			//不是第一个的话就加上与前一个的坐标差再加采摘时间。
    			a[i].time = a[i - 1].time + abs(a[i].x - a[i - 1].x) + abs(a[i].y - a[i - 1].y) + 1;
    		}
    		//如果数据合法那么就把花生数加上
    		if (a[i].time + a[i].x <= t)
    			ans += a[i].w;
    	}
    	cout << ans;
    	return 0;
    }
    

    也有人深搜的,不过这个深搜和循环也基本一样啊

    #include <iostream>
    #include <algorithm>
    using namespace std;
    typedef struct p p;
    struct p
    {
        int x,y,num;
    }s[405];
    int m,n,k,index,ans;
    int a[25][25];
    bool cmp(p a,p b)
    {
        return a.num>b.num;
    }
    void dfs(int x)
    {
        int tmp,dis;
        if(x>=index)
            return;
        if(x==0)
            dis=s[0].x;
        else
            dis=abs(s[x-1].x-s[x].x)+abs(s[x-1].y-s[x].y);
        tmp=k-dis-1;
        if(tmp>=s[x].x)///能回去
            ans+=s[x].num,k=k-dis-1,dfs(x+1);
        return;
    }
    int main()
    {
        cin>>m>>n>>k;
        for(int i=1;i<=m;i++)
            for(int j=1;j<=n;j++)
            {
                cin>>a[i][j];
                if(a[i][j])
                    s[index].x=i,s[index].y=j,s[index++].num=a[i][j];
            }
        sort(s,s+index,cmp);
        dfs(0);
        cout<<ans<<'
    ';
        return 0;
    }
    

    4.4869: 寻宝

    NOIP2012普及组T2
    真正的模拟题
    指示牌上有一个数字x,表示从这个房间开始按逆时针方向选择第x个有楼梯的房间,x的大小是1,000,000,如果直接上肯定是超时的。有没有方法能够不超时呢,我们可以使用取余,也就是考虑下周期性问题
    %10会得到[0,10),对该层楼梯门个数进行取余,会出现0导致我们现在的门又没楼梯。为了避免这种情况,房间编号我们可以从1开始,0用来存储本层楼梯通往上一层的楼梯个数。取余个数然后加上a[i]0,这样就没有问题了

    #include <bits/stdc++.h>
    using namespace std;
    //数组不要开小了,我开小get WA一次
    const int N = 10005, M = 105;
    int n, m, a[N][M], num[N][M];
    int main()
    {
    	cin >> n >> m;
    	for (int i = 1; i <= n; i++)
    		for (int j = 1; j <= m; j++)
    		{
    			scanf("%d%d", &a[i][j], &num[i][j]);
    			//a[i][0]储存本层有多少楼梯通往上一层
    			if (a[i][j])
    				a[i][0]++;
    		}
    	int t, ans = 0;
    	cin >> t;
    	//房间编号往后挪了1
    	t++;
    	for (int i = 1; i <= n; i++)
    	{
    		ans = (ans + num[i][t]) % 20123;
    		//+a[i][0]是为了防止模了之后为0(包含本层只有一个楼梯)
    		int x = num[i][t] % a[i][0] + a[i][0];
    		t--;
    		while (x)
    		{
    			t++;
    			if (t > m)
    				t = 1;
    			if (a[i][t])
    				x--;
    		}
    	}
    	cout << ans;
    	return 0;
    }
    

    5.4876: 转圈游戏

    NOIP2013提高组Day1T1
    也就是1次你走到(x+m)%n的位置,10 ^ k次为(x+ m * 10 ^ k)%n的位置
    满足随时取余定理,可以直接用快速幂进行求解

    #include <bits/stdc++.h>
    using namespace std;
    int ksm(int a, int b, int Mod)
    {
    	int ans = 1, t = a;
    	while (b)
    	{
    		//2进制位是1,就乘上,&按位与运算
    		if (b & 1)
    			ans = ans * 1LL * t % Mod;
    		t = t * 1LL * t % Mod;
    		//每次都/2,和右移(>>)一位相同
    		b >>= 1;
    	}
    	return ans;
    }
    int main()
    {
    	int n, m, k, x;
    	cin >> n >> m >> k >> x;
    	cout << (x % n + m % n * ksm(10, k, n) % n) % n;
    	return 0;
    }
    

    6.4879: 积木大赛

    NOIP2013提高组Day2T1
    不用线段树,也不用递归,可以直接模拟
    我们可以把序列分成(a1,..ai)(ai+1,...aj)......(ak,...an)多个非递减序列。
    然后所有段中最大值的和减去除第一段外的段的最小值,那么直接记录两个数字的差是否可以呢
    设q为左边一堆高度,p为右边一堆高度,s为总摆放次数。
    1.q<p,即左边的一堆比右边矮,左边的一堆摆完后,右边的还差一点,那么摆放次数s加上两堆的高度差p-q(相当于摆好了右堆)。
    2.q>=p,即左边的一堆比右边矮,说明只要左边的一堆堆好了,那么右边的一堆也肯定堆好了,所以不需要增加摆放次数s。
    所以猜测是正确的

    #include <bits/stdc++.h>
    using namespace std;
    int main()
    {
    	int n, last = 0, ans = 0;
    	cin >> n;
    	for (int i = 0,x; i < n; i++)
    	{
    		cin >> x;
    		//左边低,需要加上
    		if (x > last)
    			ans += (x - last);
    		last = x;
    	}
    	cout << ans << endl;
    }
    

    7.4886: 生活大爆炸版石头剪刀布

    NOIP2014提高组Day1T1
    直接写出这个输赢表即可,一个一个写if累死了,同理的还有TZOJ5137: 骰子

    #include <bits/stdc++.h>
    using namespace std;
    //直接写出这个输赢表
    int ce[5][5] = {
    	0, -1, 1, 1, -1,
    	1, 0, -1, 1, -1,
    	-1, 1, 0, -1, 1,
    	-1, -1, 1, 0, 1,
    	1, 1, -1, -1, 0};
    int a[205], b[205];
    int main()
    {
    
    	int n, na, nb;
    	cin>>n>>na>>nb;
    	for (int i = 0; i < na; i++)
    		cin >> a[i];
    	for (int i = 0; i < nb; i++)
    		cin >> b[i];
    	int apos = 0, bpos = 0, awin = 0, bwin = 0;
    	for (int i = 1; i <= n; i++)
    	{
    		if (ce[a[apos]][b[bpos]] == 1)
    			awin++;
    		if (ce[a[apos]][b[bpos]] == -1)
    			bwin++;
    		apos++;
    		bpos++;
    		//到尾从头开始
    		if (apos == na)
    			apos = 0;
    		if (bpos == nb)
    			bpos = 0;
    	}
    	cout<<awin<<" "<<bwin;
    	return 0;
    }
    
    
  • 相关阅读:
    day_01 python基础 基本数据类型 if条件
    计算多边形周长和面积
    我研究出来的属性查询,贴自己的代码,请大家指教
    配置sde
    如何编辑SDE数据库(转载)
    ArcSED连接方式
    不同窗体传递数据
    sde stuff
    ArcSED
    不显示查询问题的解决(太完美了,新建一个图层,表示查询结果)
  • 原文地址:https://www.cnblogs.com/BobHuang/p/13898850.html
Copyright © 2011-2022 走看看