SUMMARY

① 将一个十进制的数转化成base进制的数(想原理)

    while(val) {  
        t[count++] = val % base;     //val中有多少个base。(因为形式中每个数必须<进制数base,所以取余)
        val /= base;                 //循环n次,则此行得到val中有多少个base的n次方。
                                     //显然,这里得到的t数组表示的形式是反过来的。
    }  

②将一个base进制的数转化成十进制值(想原理)

    ans = 0;  
    weight = 1;  
    while(val) {  
        r = val % 10;  //先取出各个位上的数  
        val /= 10;  
  
        if(r >= base)   //如果某位上的数大于其进制数了,肯定是不合理的。
            return -1;  
  
        ans += weight * r;   //weight表示每个位上的一个权值
  
        weight *= base;  
    }  
  
    return ans;  

异或:a^x=v可推出a=v^x和x=a^v

异或:

因为a^a=0,那么要找出单独的数(唯一一个出现奇数次的数),只需要将所有的数进行异或运算即可。

要求异或和,初始值sum设为0

Ctrl+H记事本替换内容。

多位小数输出用printf("%lf",a);

⑦ 

回文串的查找(动态规划):dp[i][j](bool型)表示i~j是不是一个回文串,循环外->内依次是:len长度,起点i,终点j,转移方程是若dp[i+1][j-1]==true,dp[i][j]=true。注意之前要先初始化好dp[i][i]和连续相同的dp[i][i+1]为true。

最后的string的截取子串函数为substr(起点,子串长度)

    string longestPalindrome(string s) {  
        int n = s.length();    
  int longestBegin = 0;    
  int maxLen = 1;    
  bool table[1000][1000] = {false};    
  for (int i = 0; i < n; i++) {    
    table[i][i] = true;    
  }    
  for (int i = 0; i < n-1; i++) {    
    if (s[i] == s[i+1]) {    
      table[i][i+1] = true;    
      longestBegin = i;    
      maxLen = 2;    
    }    
  }    
  for (int len = 3; len <= n; len++) {    
    for (int i = 0; i < n-len+1; i++) {    
      int j = i+len-1;    
      if (s[i] == s[j] && table[i+1][j-1]) {    
        table[i][j] = true;    
        longestBegin = i;    
        maxLen = len;    
      }    
    }    
  }    
  return s.substr(longestBegin, maxLen);    
    }  

注意动态规划中dp数组的定义 从而正确写出状态转移方程。比如说问机器人的路线这道题:

 dp[i][j]=dp[i-1][j]+dp[i][j-1];  

类似于爬楼梯的方案数:

 int climbStairs(int n) {  
        int dp[n+1];  
        for(int i=0;i<=n;i++)  
        {  
            if(i==0)  
            {  
                dp[i]=0;continue;  
            }  
            if(i==1)  
            {  
                dp[i]=1;continue;  
            }  
            if(i==2)  
            {  
                dp[i]=2;continue;  
            }  
           dp[i]=dp[i-1]+dp[i-2];   //到了第i步有多少种不同走法总数取决于跨一步前的走法数+跨两步前的走法数  
            
        }  
        return dp[n];  

“方案数”的这种动态规划,我再强调一次,记住了,要注意初始值(临界值)!!!!!


求最值的dp(如果是在连续的段上操作)则不一定要用max/min函数,而是用“拖累思想”(我前面的dp有没有拖累当前的元素):

(1)求最大子段和

        for(int j=2; j<=n; j++) {  
            cin >> now;  
  
            if(0 > sum)  
                // 不单调递增时(之前子段和为负)==》“拖累”了当前元素,把当前的元素预存为另外的一个子段  
                sum = now, sumstart = j;  
            else  
                // 单调递增  
                sum += now;  
  
            // 当前正在进行计算的最大子段和超过之前的最大子段和,则重置最大子段和  
            if(sum > max)  
                max = sum, maxstart = sumstart, maxend = j;  
        }  

(2)求最大子矩阵和

起点行i,终点行i,起点列k。s[k]是“竖条和”。

    for(i=1;i<=n;i++)  //起点行
    {  
        memset(s,0,sizeof(int)*510);  
        for(j=i;j<=n;j++)   //终点行
        {  
            for(k=1;k<=m;k++)   //列上的遍历
            {  
                s[k] += a[j][k];  
                          
                if(dp[k-1] > 0)     //状态转移——“拖累思想”。若dp[k-1]>0则不会拖累当前数。
                {  
                     dp[k] = dp[k-1]+s[k];    
                }else{  
                     dp[k] = s[k];  
                }  
              
                if(dp[k]>max)  
                {  
                    max = dp[k];  
                }  
            }  
        }  
    }  

我突然在想,这种连续的即每个元素都要放入的(和背包问题的“选放”区别)的dp状态转移方程,感觉一般是和dp[i-1]或者dp[i-2]什么的就近找关系,不用拉很远。


10.

八皇后问题+N皇后问题

两个函数:place(int q),attack(int q, int i)。主要是前两个函数,place要递归(注意一个皇后可能有多个不同摆放位置-->多方案),皇后序号即其所放置的行号。place是给你找列号,attack是看你用这个列号的话会不会和之前摆好的冲突,如果能摆好的话place递归去摆下一个,或者进入下次循环给当前重新摆个位置。

bool attack(int p,int qq)  
{  
    if(p==1)  
        return false;</span>  
    else  
    {  
        for(int i=1;i<p;i++)  
        {  
            if(q[i]==qq)  
                return true;  
            if(abs(q[i]-qq)==abs(i-p))  
                return true;  
        }  
        return false;  
    }  
}  
  
  
void place(int p)  
{  
    if(p==9)  
    {  
        total_solution+=1; return;
    }  
    for(int i=1;i<=N;i++) //对第p行的列上递归  //N是皇后数量,也是行、列数 
    {  
        if(attack(p,i)==false)  
        {  
            q[p]=i;  
            place(p+1);  
        }  
    }  
}  

11.

*+表达式求值:

a*b+c

a存在temp里,遇到*,tempx*=temp,b存在temp里,遇到+则让tempx*=temp再加到ans里,c存在temp里,到末尾了,如果tempx为1(即之前都被加到ans里了),则ans+=temp,否则则知道最后一个符号其实是*,应该让tempx*=temp再加到ans里。

就是一种顺序处理的逻辑设计,举个例子想想多种情况,考虑全面一点,进行完善的程序设计。


12.

【二进制枚举】

比如说有14次,每次可能有两种情况,就能用到二进制枚举。

李白喝酒:

int main(){  
    int ans=0;//方案数  
    for (int i=0; i<(1<<14); i++) {  
        int dian=0;//表示遇到店的次数  
        int hua=0;//表示遇到话的次数  
        int num=2;//初始酒壶有两斗  
        for (int j=0;j<14 ;j++) {  
            if (i&(1<<j)) {//这里判断二进制i从右数第j+1为是否为1  //注意这里写法哟 不能==1什么的
                dian++;//遇到店,次数加1  
                num*=2;//加一倍  
            }else{  
                hua++;//遇到花,次数加1  
                num-=1;//喝一斗  
            }  
        }  
        if (dian==5&&hua==9&&num==1) {  
            ++ans;//记录方法数  
        }  
    }  
    printf("%d\n",ans);  

13.

蔡算星期几公式:

w=(d+2*m+3*(m+1)/5+y+y/4-y/100+y/400)%7 

结果再+1则为真正的星期几啦~

注意每年的1、2月要当做上一年的13、14月来算(即y-1 m取13、14)


14.

字符小写转大写:-=32


15.




16.

【map】

直接dict["Tom"]=1相当于插入效果。

可以count看看存不存在。

遍历:map<string,int> iterator:: it=dict.begin();it!=dict.end();it++


17.

map排序:

map本身就是按键值对的first(key-value)在插入的时候就自动排序了的,但如果想让map从大到小排序或者按自定义的顺序排序,显然需要用到sort函数结合cmp函数。但是map是不能去sort的,sort只能针对线性。

解决方法就是定义一个vector来存map的东西:vector<pair<string,int> >vec(dict.begin(),dict.end()),然后对vector来sort。

bool cmp(pair<int,int>&a,pair<int,int>&b)   //①自定义计算机的"小于"   
{  
    if(a.second>b.second)  
        return true;  
    else if(a.second==b.second && a.first>b.first)  
        return true;  
    else  
        return false;     //这个else语句一定不能漏掉  
}  
  
int main()  
{  
    map<int,int> m;  
    int n;  
    cin>>n;  
    while(n--)  
    {  
        int a;  
        cin>>a;  
        if(m.count(a)==0) m[a]=0;   //②  
        m[a]++;  
    }  
    vector<pair<int,int>>vec(m.begin(),m.end());      //③  
    sort(vec.begin(),vec.end(),cmp);  
    cout<<vec.begin()->first<<" "<<vec.begin()->second;  
    return 0;  
}  

18.

【队列】

敲7:

n个人,第m个人开始报报的t,数里有7或是7的倍数的出局,求最后剩下的一个人。

利用“队列前出后插的定义”,想象把这个圆桌拉成一条线(一个队伍),遵守先进先出的原则。如果数里有7则直接pop,否则的话就乖乖从队头出来,插入到队伍后面去(等着下次轮到你报数)。


任务系统:

蒜头君设计了一个任务系统。这个系统是为了定时提醒蒜头君去完成一些事情。

系统大致如下,初始的时候,蒜头君可能会注册很多任务,每一个任务的注册如下:

Register Q_num Period

表示从系统启动开始,每过 PeriodPeriod 秒提醒蒜头君完成编号为 Q_{num}Qnum 的任务。

你能计算出蒜头君最先被提醒的 kk 个任务吗?


发现没有?跟敲7为啥都用队列呢?因为其实都可以理解成“一个事物这次来了之后,下次还会来,就跟在排队一样,排到了又重新去排队等待”!!!!!

这里用优先队列,自动让队列排序。但是!这个要注意了,是我自定义的结构体作为了优先队列的元素,而优先队列的排序将会遵守我结构体里定义的“bool operator <(const node &b) const”函数的定义。(男左女右,应该没得问题的)


    while(k--)  
    {  
        printf("%d\n",q.top().num);  
        s1=q.top();  
        s1.times+=1;  
        s1.period=s1.times*s1.onetime_period;  
        q.pop();  
        q.push(s1); //再去排队(此处为优先队列则自动排序~)  
    }  

19.【优先队列】【n个最小和】

思想:我跟你现在是最小的了,那么说明我牛逼,我跟你后面那个可能也会是下一次的最小的~~

#include<iostream>  
#include<queue>  
#include<bits/stdc++.h>  
using namespace std;  
const int mmax=50010;  
int A[mmax],B[mmax];  
struct Item  
{  
    int s,b;  
    Item(int s,int b):s(s),b(b){}  
    bool operator < (const Item &b) const  
    {  
        return s>b.s;  
    }  
 }   
   
 priority_queue<Item> q;  
 int main()  
 {  
    int n;  
    cin>>n;  
    for(int i=0;i<n;i++)  
    {  
        cin>>A[i];  
    }  
    for(int i=0;i<n;i++)  
    {  
        cin>>B[i];  
    }  
    sort(A,A+n);  
    sort(B,B+n);  
    for(int i=0;i<n;i++)  
    {  
        q.push(Item(A[i]+B[0],0));  
    }  
    for(int i=0;i<n;i++)  
    {  
        Item item=q.top();  
        q.pop();  
        cout<<item.s;  
        if(i!=n-1)  
            cout<<" ";  
        int b=item.b;  
        if(b+1<n)  
            q.push(Item(item.s-B[b]+B[b+1],b+1));  
    }  
    return 0;  
 }  

20. 

走迷宫路数 dfs(x,y,n,m,a[][]) :x y是当前到达的点的坐标,n m是图形的行和列数,a数组是输入的图形

dfs临界条件是达到终点‘T’,使用xx和yy数组进行移动,判断出界或者访问过则continue,在移动之后该点的vis要归回=0. (理解记忆:因为可以想象这个格子是终点的前一个格子,且唯一,那么不能只访问一次就不能访问了吧!  

21.

油田问题。

省赛有道类似题。去dfs周围的,把它那一坨的都变成其他符号,方便我主函数里的计数。


22.

方程的解数。dfs(i,sum)  :i是当前该算xi了,sum是当前已得到的和。

这道题让我觉得dfs的题有一个“题型思路上的共同点”:多个点,如果每个点有多种选择(状态),则可以通过dfs来进行“选择”,以此进行递归,注意把临界条件找到。

但这个时候如果能用dfs,很有可能可以用动态规划——尤其是问你“方案数”“路线数”的(那么dp的含义应该就是所求)!!!。

23.

蒜头君找钥匙回家。S起点,P钥匙,T家。

两次bfs最短路径,S出发找P 和 T出发找P,加和枚举能到达的P的两值之和取最小。就知道要取哪个钥匙能最短路径了。


24.


动态规划的思考!先把dp含义想好之后,感觉可以考虑考虑i-1 或者 i-2 (减得很少或者减得是特殊数据)的 dp ,思考状态转移方程。


25.

传娃娃游戏。只能左右传一人,问从A开始传传m次回到他手里,有多少种传法。

刚开始觉得,诶?多个点?每个点有两种选择。。dfs??要明白,dfs可能就是可以用动态规划来做的!!!况且这里是求“路线数”“方案数”,多半动态规划了!dp数组含义就是“方案数”!这时候想dp的下标然后想转移方程。咦?如果觉得下标选取一下没思路,就把题目中的变量都列出来,挨个组合看看弄一维还是二维啥的!这里dp[i][j] i为传到了第i次,j为同事序号,这样状态方程及其好些!


26.

strstr(s,subs) 可以用来查找子串(返回值为子串index,没有则返回NULL)!

可以用strstr来“看看子串存不存在”,而一看就是那种复杂度会比较大的字符串匹配题肯定还是用算法。


27.

卡特兰数:先把n个以1~n编号看作第一组,另外n个看作第二组,第二组中的每一个可以选择去匹配第一组中的任意一个。所有方案总数即h[n]。

这个理解肯定没问题,再看看应用:https://blog.csdn.net/hackbuteer1/article/details/7450250


28.

动态规划——两条不相交的走迷宫。简化题意后发现就是走两条迷宫里的路 不相交即可,dp[i][j][k][d]。转移方程是2*2=4种。


29.


多重背包来做。dp[half]==half即可。


30.

https://blog.csdn.net/m0_38033475/article/details/79497154

【状态压缩dp】【子集i、补集i^t】

求移除字符串的最小操作数,回文串可以一次性移除。

其实状压dp就是把“下标”变为“二进制数”以表示“选取情况”“组合方案”!

dp[t]表示选取情况为t时的最小操作次数。

这里假设t为选取情况,若t是回文串,那么dp[t]=1,否则=inf,需要去看选取t的子集和补集之和(dp[i]+dp[i^t])取最小值,从而知道dp[t]的最小值。


船运载小车。(这道题好好看理解一下,融会贯通)完全可以类比字符串移除那道题!!!dp[t]表示选取情况为t时的最大破损值。

状态压缩dp:

①n很小,不超过20

②组合问题(选取问题——二进制枚举来表示选取情况)

③求最值(直接联想到动态规划)


31.

【蓝桥杯】运用欧几里得求最大公约数解题

https://blog.csdn.net/m0_38033475/article/details/79506342


32.

素数打表。求范围内相邻素数的最小和最大距离

https://blog.csdn.net/m0_38033475/article/details/79508290


33.










评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值