第五周 周结(分治算法)

训练内容:

信息学奥赛一本通 分治算法
题目链接:http://ybt.ssoier.cn:8088/index.php

分治算法简单理解:

分治算法和贪心本质是一样的,就是一种代码思维,而不是一种编程的框架。本次训练基本上是用递归来实现的。

分治算法核心是:分而治之,就是将原问题划分成n个规模较小,并且和原问题相似的子问题,递归的去解决这些问题,然后将结果合并,最后得到原问题的答案。

分治算法的递归实现中,每一层递归都包含了这样三个操作:
1,分解:将原问题分解成一系列子问题。
2,解决:递归地求解各个子问题,若子问题足够小,则直接求解。
3,合并:将子问题的结果合并成原问题。

分治算法原则如下:
1,原问题和子问题使用相同的计算模式
2,子问题之间相互独立,不会相互影响
3,当子问题足够小,可以直接求解出答案
4,子问题解决后,还可以合并为原问题期望的结果,而且合并的时间复杂度要低于原问题直接解决的时间复杂度

本周训练感悟:

本次训练先了解了分治算法,做题过程中分不出最小问题的情况(比如以下黑白棋子的移动),导致做题有点慢,还有的题目是有规律的(比如以下的2011题),个人感觉对二分法的掌握也蛮熟练了,再接再厉吧!!

题目整理:

黑白棋子的移动:

【题目描述】
有2n个棋子(n≥4)排成一行,开始位置为白子全部在左边,黑子全部在右边,如下图为n=5的情形:

○○○○○●●●●●

移动棋子的规则是:每次必须同时移动相邻的两个棋子,颜色不限,可以左移也可以右移到空位上去,但不能调换两个棋子的左右位置。每次移动必须跳过若干个棋子(不能平移),要求最后能移成黑白相间的一行棋子。如n=5时,成为:

○●○●○●○●○●

任务:编程打印出移动过程。

【输入】
输入n。

【输出】
移动过程。

【输入样例】
7
【输出样例】
step 0:ooooooo*******–
step 1:oooooo–o
step 2:oooooo
*–o*
step 3:ooooo–oo
step 4:ooooo
–oo
step 5:oooo–ooo
step 6:oooo
***–ooo*
step 7:ooo–oooo*
step 8:oooo**–ooo*
step 9:o–o**ooooo*
step10:ooo*–oooo
step11:–ooooooo*
题目理解:
中问题,理解肯定没问题;
题目解析:
因为棋子每次都是按规律先一半白后一半黑的,所以每次把最中间的两个也就是一黑一白移动到最后就可以,当然还要加上最后的“–”也就是把最后的“–”再移动到中间的空位就可以了。(我觉得正常人一开始都这样想)
我一开始确实是这样想的,哈哈哈但是后来发现不对。
首先我们看n=4时;
初始时:○○○○●●●●
第1步:○○○——●●●○●(—表示空位)
第2步:○○○●○●●——●
第3步:○——●○●●○○●
第4步:○●○●○●——○●
第5步:——○●○●○●○●
是不是跟我们想的不太一样呢;
但是当试n=5时;
初始时:○○○○○●●●●●
第1步:○○○○——●●●●○●
第2步:○○○○●●●●——○●
……
是不是就是我们想的那样呢 所以我们只需要特殊考虑n=4就好了。代码如下:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<string>
#define INF 999999999
#define N 1001
#define MOD 1000000007
using namespace std;
int n, cnt, space;
char a[N];
void print()
{
    printf("step%2d:", cnt++);
    for(int i=1; i<=2*n+2; i++)
        printf("%c",a[i]);
    printf("\n");
}
void move(int m)
{
    a[space] = a[m];
    a[space+1] = a[m+1];
    a[m] = a[m+1]='-';
    space = m;
    print();
}
void mv(int m)
{
    if(m==4)
    {
        move(4);
        move(8);
        move(2);
        move(7);
        move(1);
    }
    else
    {
        move(m);
        move(2*m-1);
        mv(m-1);
    }
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)	 
        a[i]='o';
    for(int i=n+1;i<=2*n;i++)
        a[i]='*';
    for(int i=2*n+1;i<=2*n+2;i++)
        a[i]='-';
    cnt = 0;
    space = 2*n+1; 
    print();
    mv(n);
    return 0;
}
2011题:

【题目描述】
已知长度最大为200位的正整数n,请求出2011n的后四位。

【输入】
第一行为一个正整数k,代表有k组数据(k≤200),接下来的k行,每行都有一个正整数n,n的位数≤200。

【输出】
每一个n的结果为一个整数占一行,若不足4位,去除高位多余的0。

【输入样例】
3
5
28
792
【输出样例】
1051
81
5521
题目理解:
老样子中问题肯定理解啦;(仪式感不能丢)
题目解析:
我一看题目n的位数……必然是int的范围不够呀,肯定要用字符的,(编程小白的蜜汁自信)但是之后呢 就蒙了,咋整呢应该(然后就开始“猜题”就是猜为啥是2011而不是别的,所以就百度了一下)发现2011^500%10000=1也就是每500就是一个循环,我们对n操作n%500再去求2011的n次方就好了,因为1000%500=0也就是最后答案只和n的后三位有关,当然n==0时答案为1;代码如下:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<cmath>
#include<map>
#include<iomanip>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;
int k,zs,sum;
string n;
int main()
{
    cin>>k;
       while(k--)
    {
        zs=0;
        sum=1;
        cin>>n;
        int len=n.size();
        if(len>3)
        {
            for(int i=len-3; i<len; i++)
                zs=zs*10+(n[i]-'0');
        }
        else
        {
            for(int i=0; i<len; i++)
                zs=zs*10+(n[i]-'0');
        }
        zs%=500;
        for(int i=1;i<=zs;i++)
            sum=sum*2011%10000;
        cout<<sum<<endl;
    }
}
Great minds have purpose, others have wishes.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
我学习了关于cache数据库的相关知识,以下是我的学习周结: 1. 缓存数据库的概念和作用:缓存数据库是一种用于高速读取、写入和数据处理的数据库,它可以大幅提高应用程序的性能和响应速度。缓存数据库通常会将热点数据存储在内存中,从而快速响应应用程序的请求。 2. 缓存数据库的分类:缓存数据库根据数据存储方式的不同分为本地缓存和分布式缓存。本地缓存是指将数据存储在应用程序所在的服务器上,而分布式缓存则是将数据存储在多个服务器上,以实现负载均衡和高可用性。 3. 缓存数据库的常见技术:常见的缓存数据库技术包括Memcached、Redis、Ehcache等。这些技术在不同场景下具有不同的优势和适用性。 4. 缓存数据库的应用场景:缓存数据库通常用于需要频繁读取数据、读写比例不平衡或需要快速响应的应用程序中,如电商网站、社交网络、游戏等。 5. 缓存数据库的设计和优化:缓存数据库的设计和优化需要考虑数据访问模式、缓存失效策略、缓存容量和数据一致性等因素,以实现高效的缓存处理。 通过本的学习,我对缓存数据库的概念和应用有了更深入的了解,并且了解了常见的缓存数据库技术和应用场景。在未来的学习和实践中,我将更加深入地掌握缓存数据库的设计和优化技术,为应用程序的性能提升做出更大的贡献。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值