• 2/17qbxt笔记


    缓存机制

    在电脑中有一种比内存读入还要快的东西叫做缓存,其定义是对于从内存里读入一个数组时,计算机会预测剩余的连续的部分数组是否会被用到,所以将他存进缓存,这样可以直接按顺序读入,不用查询,更加快。

    那么对于我们的二维数组 (f[i][j]) 他是以长度为 (1 imes j)(i) 个线段组成一个线性的长链,所以连续的数字之间是 (f[1][1],f[1][2]), 而并不是 (f[1][1],f[2][1]),

    那么推广到我们的 (for) 循环上,若我们按照外层 (i),内层 (j) 的顺序循环,得到的数组就是按照计算机存储顺序调用,因此可以直接从缓存里读入 ,但是当我们反过来,计算机无法预测我们的顺序,即缓存中的数组是无用的(当前),那么只能调用内存,时间的差距大约在 (10)左右

    所以说对于循环的枚举顺序关系到时间复杂度是很重要的.尤其是矩阵乘除,不同的运输顺序造成的极值可达 (4) 倍,这就是后几个点被卡的原因,特别亏。

    二分

    解决问题,有 (m) 询问,数列已经排好序,求出小于 (x) 的有多少个

    思路

    知道最大的 (a_i<= x) ,那么就可以说答案就是 (i)

    int n,m,a[B];
    
    int main() {
      n=read(),m=read();
      for (int i=1;i<=n;i++) a[i]=read();
      sort(a+1,a+1+n); 
      while(m--)
      {
        int x=read();
        int l=1, r=n, ans=0;
        while(l<=r)
        {
          int mid=(l+r)>>1;
          if(a[mid]<=x) l=mid+1, ans=mid;
          else r=mid-1;
        }
        printf("%d
    ",ans);
      }
      return 0;
    }
    
    

    二分答案

    给定 (N) 根绳子,要求你从中分出 (K) 段绳子,使得每段绳子长度一样并且必须是整数,问这 (K) 段绳子最长能够是多少。

    思路

    这个题应该好好地说一下,浪费了我一下午,让我的对doubleint有了重新的认识

    做法的话很简单,二分长度 看行成的段数是否大于 (K),二分答案就好了

    但是这个题需要用的精度,因为在二分的过程中得到的数始终是小数,但是我们定义的是整形,所以会无限死循环

    再就是在最后的强制类型转换中,我发现了三种不用的输出方式,得到了三种不同的分数,过程惨痛

    cout<<a;
    

    这样直接是双精度输出,没什么变化

    printf("%.f",a)
    

    这个可神了,居然会自动四舍五入,太神奇了,我才知道,答案部分正确

    int s=(int)a;
    cout<<s;
    

    强制类型转换,这个就可以将整数部分完整的得到了,这也是最后的正确答案,

    double s[B],sum;
    const double esp=1e-8;
    int n,k;
    
     main() {
    //  freopen(".in", "r", stdin);
    //  freopen(".out", "w", stdout);
      cin>>n>>k;
      double mx=0;
      for (int i=1;i<=n;i++)
      {
        cin>>s[i];
        mx=max(mx,s[i]);
      }
      double l=0,r=mx;
      while(l+esp<r) 
      {
        double mid=(l+r)/2;
        int num=0;
        for (int i=1;i<=n;i++)  num+=s[i]/mid;
        if(num>=k) l=mid;
        else r=mid;
      }
      int s=(int)l;
      cout<<s;
      return 0;
    }
    

    贪心

    国王游戏

    怎么对大臣排序???

    绝对按照右手排,貌似不对,md

    假设 (n==2) 时候的到一种 (cmp) 的函数,然后直接排序就可以了,这就是贪心,信息学是一门不需要证明的许可,不用证明,对于(\%90) 的贪心题都可这么做,(nb)

    思路

    我们不妨设 (n=2) 时,最大获益金币的人最小

    那第一个人 (A)(a.r,a.l), 第二个人 (B)(b.r,b.l)

    设皇上的左右手分别为 (z[0].l, z[0].r)

    (A)(B) 的前边时

    (A) 的钱

    [frac{z[0].l}{a.r} ]

    (B) 的钱

    [frac{z[0].l imes a.l}{b.r} ]

    答案 (v1)(max{frac{z[0].l}{a.r},frac{z[0].l imes a.l}{b.r}})

    (B)(A) 前面时

    同理可得答案 (v2)(max{frac{z[0].l}{b.r},frac{z[0].l imes b.l}{a.r}})

    最终答案就是 (max{v1,v2})

    那么当 (n!=2) 时呢,假设现在就这两个人需要我们讨论,我们不是需要国王到自己前面人左手的数嘛,我们设这个数为 (x) 那么式子的就是变成

    [v1=max{frac{x}{a.r},frac{x imes a.l}{b.r}}\ v2=max{frac{x}{b.r},frac{x imes b.l}{a.r}}\ ]

    答案就是 (ans=max{v1,v2})

    当我们把分母去掉即,(v1,v2) 都乘以(a.r imes b.r)

    化简得

    [v1=max{b.r imes x,x imes a.l imes a.r}\ v2=max{a.r imes x,x imes b.l imes b.r}\ ]

    我们发现 (x) 可以消掉,即在这里答案的大小不受 (x) 的影响,那么我们的式子就可以变成

    [v1=max{b.r,a.l imes a.r}\ v2=max{a.r, b.l imes b.r}\ ]

    有了式子我们就可以利用冒泡排序,时间复杂度为 (O(n^2))

    //冒泡排序
    #include <iostream>
    
    using namespace std;
    
    struct node{
    	int l,r;
    };
    node z[100010];
    
    int cmo(node a, node b)//a是否放在b的前面
    {
    	int v1 = max(z[0].l/a.r, z[0].l*a.l / b.r);
    	int v2 = max(z[0].l/b.r, z[0].l*b.l / a.r);
    	
    	if(v1<v2) return 1;
    	else return 0;
    }
    int main()
    {
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<n;j++)
    		{
    			if(cmp(z[j+1],z[j])) swap(z[j+1], z[j]);
    		}
    }// O(n^2)
    

    其实就变成了比较这四个数的大小,这样就可以进行贪心了

    贪心式子是否可以优化呢

    我们不难发现 (b.r<b.l imes b.r)(a.r<a.l imes a.r)

    那么我们比较这是两个还有意义嘛,他们两个本质上就比右侧的大,所以剔除就好了,因此式子就化简成

    [ans=max{b.r imes b.l, a.r imes a.l} ]

    贪心化简的本质

    1. 去分母
    2. 去除公共项
    3. 出去无用项,即不可能更好
    4. 简化完毕!
    struct node{
      int l, r;
    };
    
    node z[B];
    int ans=1, n;
    
    int cmp(node a, node b)
    {
      return a.l*a.r<b.l*b.r;
    }
    
    int main() {
      scanf("%d",&n);
      scanf("%d%d",&z[0].l,&z[0].r); 
      for (int i=1;i<=n;i++)
        scanf("%d%d",&z[i].l,&z[i].r);
        
      sort(z+1,z+1+n,cmp);
      for (int i=0;i<n;i++) ans*=z[i].l;
      printf("%d",ans/z[n].r);  
      return 0;
    }
    

    高精做法

    #include <bits/stdc++.h>
    using namespace std;
    int now[20010],sum[20010],ans[20010],add[20010];
    struct Node {
        int a;
        int b;
        long long a_b;
    }node[1010];
    int read() {
        int ans=0,flag=1;
        char ch=getchar();
        while( (ch>'9' || ch<'0') && ch!='-' ) ch=getchar();
        if(ch=='-') flag=-1,ch=getchar();
        while(ch>='0' && ch<='9') ans=ans*10+ch-'0',ch=getchar();
        return ans*flag;
    }
    void times(int x) {
        memset(add,0,sizeof(add));
        for(int i=1;i<=ans[0];i++) {
            ans[i]=ans[i]*x;
            add[i+1]+=ans[i]/10;
            ans[i]%=10;
        }
        for(int i=1;i<=ans[0]+4;i++) {
            ans[i]+=add[i];
            if(ans[i]>=10) {
                ans[i+1]+=ans[i]/10;
                ans[i]%=10;
            }
            if(ans[i]!=0) {
                ans[0]=max(ans[0],i);
            } 
        }
        return ;
    }
    int divition(int x) {
        memset(add,0,sizeof(add));
        int q=0;
        for(int i=ans[0];i>=1;i--) {
            q*=10;
            q+=ans[i];
            add[i]=q/x;
            if(add[0]==0 && add[i]!=0) {
                add[0]=i;
            }
            q%=x; 
        }
        return 0;
    }
    bool compare() {
        if(sum[0]==add[0]) {
            for(int i=add[0];i>=1;i--) {
                if(add[i]>sum[i]) return 1;
                if(add[i]<sum[i]) return 0;
            }
        }
        if(add[0]>sum[0]) return 1;
        if(add[0]<sum[0]) return 0;
    }
    void cp () {
        memset(sum,0,sizeof(sum));
        for(int i=add[0];i>=0;i--) {
            sum[i]=add[i];
        }
        return ;
    }
    bool cmp(Node a,Node b) {
        return a.a_b<b.a_b;
    }
    int main() {
        int n=read();
        for(int i=0;i<=n;i++) {
            node[i].a=read(),node[i].b=read();
            node[i].a_b=node[i].a*node[i].b;
        }
        sort(node+1,node+n+1,cmp);
        ans[0]=1,ans[1]=1;
        for(int i=1;i<=n;i++) {
            times(node[i-1].a);
            divition(node[i].b);
            if(compare()) {
                cp();
            }
        }
        for(int i=sum[0];i>=1;i--)
            printf("%d",sum[i]);
        return 0;
    } 
    

    输入输出优化

    快出

    char s[10000000];
    int l=0;
    
    void print(int x)
    {
    	int y=0,z=0;//倒写
    	while (x!=0)
    	{
    		y=y*10+x%10;
    		z++;
    		x/=10;
    	}
    	for (int a=1;a<=z;a++)
    	{
    		s[l++]=y%10+'0';
    		y/=10;
    	}
    	s[l++]='
    ';
    }
    

    空间的计算方法

    • (char) 1 字节
    • (int) 4字节
    • (long long) 8 字节
    • (1M=1024K)
    • (10^7=10M)

    搜索

    • BFS
    • DFS

    题型: 给 (N) 个数选 (k) 个数

    求和最小---最优解问题

    求方案数---解数量问题

    给出一种符合条件的方案---可行解问题

    如何判断使用哪种搜索手段

    BFS

    1. 必须最优解问题,从当前状态到另外一个状态代价变化 必须为1

    DFS

    1. ,剩下的都是DFS

    搜索优化

    可行性剪枝

    明显不可能的解直接扔掉

    最优性剪枝

    不可能成为最有解的剪枝

    void dfs(int p, int nowsum, int nowuse)//考虑地p,和为nowsum,选了nowuse个数
    {
        if (nowuse>k) return;//可行性剪枝
        if (nowuse + n-p+1 < k) return;//可行性剪枝
        if (nowsum>=ans) return;//最优性剪枝
    	if(p>n)
    	{
    		ans=min(nowsum,k);
    		return;
    	}
    	dfs(p+1,nowsum,nowuse);
    	dfs(p+1,nowsum+a[p];nowsue+1);
    }
    int main()
    {
    	scanf("%d",&n);
    	for (int i=1;i<=n;i++)
    		scanf("%d",&a[i]);
    	dfs(1,0,0);
    	printf("%d",ans);
    	return 0;
    }
    

    搜索顺序优化

    如果排序后再接搜索的话,搜索顺序会受到影响,即先搜索可行性优解

    可以选择可以使答案更好或者更快地到答案的题

    靶心数

    void dfs(int p, int nowsum, int nowuse)//考虑地p,和为nowsum,选了nowuse个数
    {
        if (nowuse>k) return;//可行性剪枝
        if (nowuse + n-p+1 < k) return;//可行性剪枝
        if (nowsum>=ans) return;//最优性剪枝
    	if(p>n)
    	{
    		ans=min(nowsum,k);
    		return;
            
    	}
        dfs(p+1,nowsum+a[p];nowsue+1);
    	dfs(p+1,nowsum,nowuse);
    
    }
    int main()
    {
    	scanf("%d",&n);
    	for (int i=1;i<=n;i++)
    		scanf("%d",&a[i]);
        sort(a+1,a+1+n);
    	dfs(1,0,0);
    	printf("%d",ans);
    	return 0;
    }
    

    靶心数独

    struct node{
      int rank,sum;
    }cou[10];
    
    int a[10][10],hang[10][10],lie[10][10],gong[10][10],s[100][4],u,ok,most=-1,have;
    
    bool cmp(node a,node b)
    {
      return a.sum<b.sum;
    }
    
    void dfs(int p, int sorce)
    {
      if(p==u){
        if(sorce>most) most=sorce;
        return;
      }
      for (int i=1;i<=9;i++)
      {
        if(!hang[s[p][0]][i] && !lie[s[p][1]][i] && !gong[s[p][3]][i])
        {
          hang[s[p][0]][i]=lie[s[p][1]][i]=gong[s[p][3]][i]=1;
          dfs(p+1,sorce+(s[p][2]*i));
          hang[s[p][0]][i]=lie[s[p][1]][i]=gong[s[p][3]][i]=0;
        }
      }
      return;
    }
     
    int which(int i, int j)
    {
      if (i<=3){
        if (j<=3) return 1;
        else if (j<=6) return 2;
        else return 3;
      }
      else if (i<=6)
      {
        if (j<=3) return 4;
        else if (j<=6) return 5;
        else return 6;
      }
      else 
      {
        if(j<=3) return 7;
        else if(j<=6) return 8;
        else return 9;
      }
    }
    
    int point(int i,int j)
    {
      if(i==1||j==1||i==9||j==9) return 6;
      else if(i==2||j==2||i==8||j==8) return 7;
      else if(i==3||j==3||i==7||j==7) return 8;
      else if(i==4||j==4||i==6||j==6) return 9;
      else return 10;
    }
    
    int main()
    {
      for (int i=1;i<=9;i++) cou[i].rank=i;
      for (int i=1;i<=9;i++)
        for (int j=1;j<=9;j++)
          {
            cin>>a[i][j];
            if(a[i][j]>0) 
            {hang[i][a[i][j]]=lie[j][a[i][j]]=gong[which(i,j)][a[i][j]]=1; have+=a[i][j]*point(i,j);}
            else cou[i].sum++;
          }
        sort(cou+1,cou+10,cmp);//搜索顺序
        for (int i=1;i<=9;i++)
        {
          for(int j=1;j<=9;j++)
            
              if(a[cou[i].rank ][j]==0)
              s[u][0]=cou[i].rank,s[u][1]=j,s[u][2]=point(cou[i].rank,j),s[u++][3]=which(cou[i].rank,j);
             
        }
        dfs(0,have);
        printf("%d
    ",most);
        return 0;        
    }
    
    
    

    N皇后

    int n,b[B],js,c[B],d[B],a[B];
    
    int print()
    {
      js++;
      if(js<=3)
      {
        for(int i=1;i<=n;i++)
          printf("%d ",a[i]);
        puts("");
      }
    }
    void dfs(int x)
    {
      for(int i=1;i<=n;i++)
      {
        if((!b[i]) && (!c[i+x]) && (!d[x-i+n]))
        {
          a[x]=i;
          b[i]=1;
          c[i+x]=1;
          d[x-i+n]=1;
          if(x==n)
          {
            print();
          }
          else
          dfs(x+1);
          b[i]=0;
          c[i+x]=0;
          d[x-i+n]=0;
        }
      }
    }
     main() {
    //  freopen(".in", "r", stdin);
    //  freopen(".out", "w", stdout);
      n=read();
      dfs(1);
      cout<<js;
      fclose(stdin);
      fclose(stdout);
      return 0;
    }
    
    
    

    八数码

    int dx[4]={0,0,1,-1};
    int dy[4]={1,-1,0,0};
    int n;
    
     main() {
    //  freopen(".in", "r", stdin);
    //  freopen(".out", "w", stdout);
      n=read();
      queue<int>q;
      map<int,int>m;
      m[n]=0;
      q.push(n);
      while (!q.empty())
      {
        int u=q.front(),x=0,y=0;
        int n=u;
        int c[4][4];
        q.pop();
        if(u==123804765) break;
        for (int i=2;i>=0;i--)
          for (int j=2;j>=0;j--)
          {
            c[i][j]=u%10;
            u/=10;
            if(!c[i][j]) x=i,y=j;
          }
        for (int i=0;i<=3;i++)
        {
          int x1=x+dx[i],y1=y+dy[i];
          if(x1<0 || x1>2 || y1<0 || y1>2) continue;
          swap(c[x1][y1],c[x][y]);
          int sum=0;
          for (int j=0;j<=2;j++)
            for (int k=0;k<=2;k++)
            {
              sum=sum*10+c[j][k];
            }
          if(!m.count(sum))
          {
            m[sum]=m[n]+1;
            q.push(sum);
          }
          swap(c[x1][y1],c[x][y]);
        }
      }
      printf("%lld",m[123804765]);
      fclose(stdin);
      fclose(stdout);
      return 0;
    }
    
  • 相关阅读:
    Struts2笔记——ONGL表达式语言
    Struts2笔记——自定义拦截器
    Struts2笔记——Action校验器
    Struts2笔记——文件上传
    Struts2笔记——与ServletAPI解耦
    Struts2笔记——通配符和动态方法调用
    Struts2笔记——类型转换
    Struts2笔记——result结果类型
    MongoDB相关资料
    公开数据集
  • 原文地址:https://www.cnblogs.com/lToZvTe/p/14409302.html
Copyright © 2020-2023  润新知