五一 DAY1

 DAY 1        2019.4.28

 

 


 

 

 

例题1

 

题解:

 

 

 

例题2

题解:

 

 

 

 例题3

题解:

vis[ ]判断是否为素数,pri[ ]储存素数

 

 

 

 例题4

题解:

 

 

 例题5

题解:

PS: i  <  1<<n        i<2^n

        (1<<j)& i      如果2^j最后一位和 i 相同,返回1

 

 

例题6

判回文数是N√N,素数NlogN

 

 枚举:

 

 

 

 

 

1.从起点开始向四个方向扩展

2.到一个点卡死,删除栈中的位置,回到前一步继续搜

3.找到一种解

4.这也是一个解

PS:DFS不会死循环,走完一个方向就会走其他方向

 

例题:

题解:

实际上就是寻找是否存在路径小于等于T

VIS[ ][ ]判断这个坐标是否走过

PS:

1.DFS使用一遍之后清空所影响数据

2.命名变量不要重名

  每组数据开始之前ans要回归初始值

[代码]:

#include<cstdio>
#include<algorithm>

#define N 15

using namespace std;

int i,j,m,n,p,k,vis[N][N],tmp,T,ans=10000000,tot;

char c[N][N];

pair<int,int> Ans[N*N];

const int X[4]={0,0,-1,1};
const int Y[4]={-1,1,0,0};

int check(int x,int y)    //是否合法 
{
        if (x<=0||y<=0||x>n||y>n) return 0;
        if (vis[x][y]) return 0;
        if (c[x][y]=='#') return 0;
        return 1;
}

void dfs(int x,int y)
{
        if (c[x][y]=='E') 
        {
            ans=min(ans,tot);
            return;
        }
        vis[x][y]=1;
        Ans[++tot]=make_pair(x,y);
        int i;            //辅助变量,开在里面 
        for (i=0;i<4;++i)
            if (check(x+X[i],y+Y[i]))
                dfs(x+X[i],y+Y[i]);
        --tot;
        vis[x][y]=0;
}

void Main()
{
        ans=(int)1e9;
        scanf("%d%d",&n,&T);
        for (i=1;i<=n;++i) scanf("%s",c[i]+1);
        for (i=1;i<=n;++i)
            for (j=1;j<=n;++j)
                if (c[i][j]=='S') dfs(i,j);
        printf(ans<=T?"YES\n":"NO\n");
}

int main()
{
        int T;
        scanf("%d",&T);
        for (;T--;) Main(); //用一个过程实现多组数据,模块化
}

 

 

1.沿四个方向扩展

2.起点出发,四周搜,可以走,加队列

3.维护每个点距离起点的最短距离

[代码]:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<ctime>
#include<cmath>
#include<map>
#include<set>
#include<bitset>
#include<vector>

#define ls (t<<1)
#define rs ((t<<1)|1)

#define N 15
#define M 200005
#define K 17

#define pb push_back
#define fi first
#define se second
#define mk make_pair

using namespace std;

int i,j,n,m,Time;

char c[N][N];

int vis[N][N];

pair<int,int> Q[N*N];

const int x[4]={-1,1,0,0};
const int y[4]={0,0,-1,1};

int check(int x,int y)
{
        if (x<1||y<1||x>n||y>n) return 0;
        if (c[x][y]=='#') return 0;
        if (vis[x][y]!=-1) return 0;
        return 1;
}

int bfs(int sx,int sy)
{
        int i,l,r;
        memset(vis,-1,sizeof(vis));
        Q[r=1]=mk(sx,sy); vis[sx][sy]=0;
        for (l=1;l<=r;++l)
        {
                int ax=Q[l].fi,ay=Q[l].se;
                if (c[ax][ay]=='E') 
                {
                        if (vis[ax][ay]<=Time) return 1;
                        return 0;
                }
                for (i=0;i<4;++i)
                    if (check(ax+x[i],ay+y[i])) 
                    {
                            Q[++r]=mk(ax+x[i],ay+y[i]);
                            vis[ax+x[i]][ay+y[i]]=vis[ax][ay]+1;
                    }
        }
        return 0;
}

int main()
{
        int T; scanf("%d",&T);
        for (;T--;)
        {
                scanf("%d%d",&n,&Time);
                for (i=1;i<=n;++i) scanf("%s",c[i]+1);
                for (i=1;i<=n;++i)
                    for (j=1;j<=n;++j) if (c[i][j]=='S') {
                        if (bfs(i,j)) puts("YES"); else puts("NO"); 
                    }
        }
}

 

 

DFS  先扩展,不行就回头

    存储空间小

BFS  一般是求最短路径

    全部走,所有路径集合,空间大

    为所有可能的结果开数据

 

 

Pair 数组相当于一个结构体,int int两个元素,存横纵坐标

 

 

 

 Vector

Vector可以用来存图存数据

可以自己定义类型

相当于开了N个int数组,长度可以很长

 

其实相当于开了一个二维数组

相当于在数组第y行最后加入一个x

在数组第x行最后加入一个y

每一行数组表示该点可以到达的点(也就是这两个点之间联通)

弹出

[代码]:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<ctime>
#include<cmath>
#include<map>
#include<set>
#include<bitset>
#include<vector>

#define ls (t<<1)
#define rs ((t<<1)|1)

#define N 100005
#define M 200005
#define K 17

#define pb push_back
#define fi first
#define se second
#define mk make_pair

using namespace std;

vector<int>v[N];

int i,j,m,n,p,k,vis[N],Q[N],ans;

void bfs(int x)
{
        int l,r;
        Q[r=1]=x;
        vis[x]=1;
        for (l=1;l<=r;++l)
        {
                int p=Q[l];
                for (i=0;i<(int)v[p].size();++i)  //遍历所有出边 
                {
                        int k=v[p][i];      //vector类型其实相当于二维数组 
                        if (vis[k]) continue;
                        vis[k]=1;
                        Q[++r]=k;
                }
        }
}

int main()
{
    scanf("%d%d",&n,&m);
    for (i=1;i<=m;++i)
    {
            int x,y;
            scanf("%d%d",&x,&y);
            v[y].push_back(x);
            v[x].push_back(y);
    }
    for (i=1;i<=n;++i) 
      if (!vis[i]) 
      {
        bfs(i);
        ans++;
      } 
      
    cout<<ans; 
         
}

 

 

 

 

 

 

 

 

 

 PS:

            k=奇数  =>  k^=1为k=k-1

            k=偶数  =>  k^=1为k=k+1

 [代码]:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<ctime>
#include<cmath>
#include<map>
#include<set>
#include<bitset>
#include<vector>

#define ls (t<<1)
#define rs ((t<<1)|1)

#define N 1005
#define M 200005
#define K 17

#define pb push_back
#define fi first
#define se second
#define mk make_pair

using namespace std;

int i,j,m,n,p,k,r[2];

int vis[N][N];

pair<int,int> Q[2][N*N];

char c[N][N];

const int X[4]={-1,1,0,0};
const int Y[4]={0,0,-1,1};

int check(int x,int y)
{
        if (x<=0||y<=0||x>n||y>m) return 0;
        if (vis[x][y]) return 0;
        return 1;
}

void bfs(int x,int y)
{
        int i,l,now=1;
        Q[0][r[0]=1]=make_pair(x,y);
        memset(vis,-1,sizeof(vis));
        vis[x][y]=0;
        for (;;)    //死循环 
        {
            now^=1;   
            if (!r[now]) return;
            for (l=1;l<=r[now];++l)
            {
                    int ax=Q[now][r[now]].first,ay=Q[now][r[now]].second;
                    for (i=0;i<4;++i)
                        if (check(ax+X[i],ay+Y[i]))
                    {
                            int ck=c[ax+X[i]][ay+Y[i]]=='#';
                            if (!ck)            //如果可以走,加入当前队列
                            {
                                    vis[ax+X[i]][ay+Y[i]]=vis[ax][ay];
                                    Q[now][++r[now]]=make_pair(ax+X[i],ay+Y[i]);
                            }
                            else           // 否则加入暂时先不扩展的队列
                            {
                                    vis[ax+X[i]][ay+Y[i]]=vis[ax][ay]+1;
                                    Q[now^1][++r[now^1]]=make_pair(ax+X[i],ay+Y[i]);
                            }
                    }     // 维护两个不同的队列
            }
        }
}

int main()
{
    scanf("%d%d",&n,&m);
    for (i=1;i<=n;++i) scanf("%s",c[i]+1);
    for (i=1;i<=n;++i)
        for (j=1;j<=m;++j) 
            if (c[i][j]=='S') bfs(i,j);
    for (i=1;i<=n;++i)
        for (j=1;j<=m;++j) 
            if (c[i][j]=='E') printf("%d\n",vis[i][j]);
}

 

 

 

 

 

 

 

 

 

 

能BFS就BFS,否则考虑DFS

 

 

K表示有没有用过正方形

Id表示高度,不可以超边界

代码加了剪枝

 

 

 

一个固体块,确定一个小块的位置,其余小块的位置就可以确定,整个固体块也就确定了

比如,( a, b ) 第一块固体块的左上角方块坐标

          ( c , d ) 第二块固体块的左上角方块坐标

          ( e , f ) 第三块固体块的左上角方块坐标

           然后根据相对位置推出其余小块的坐标

           六维

比如,( 0 , 0 ) 第一块固体块的左上角方块坐标

           ( c , d ) 第二块固体块的左上角方块坐标

           ( e , f ) 第三块固体块的左上角方块坐标

            然后根据相对位置推出其余小块的坐标

            移动的话要根据相对位置

            状态数404

            一个四维状态

 

 

 

 

 

 

 

 


 

 

 

 

 

 

 

 

   化简一下

   ans=∑(Ai – Bi)*j+Bi*n- Ai

   Ai – Bi越小越靠后

 

 

  ∑Bi(ti-T)=0

 

 

我们会得到一半正的一半负的

正:∑Bi,ti-T

负:∑Bi,ti-T

若|正|<|负|

那么正的就全取,负的有一部分为之抵消,至于未能抵消掉的,就直接不开此水龙头

 

 [代码]:

#include<cstdio>
#include<algorithm>
#include<cstring>

#define N 300005

using namespace std;

int a[N],t[N],i,j,m,n,p,k,id[N],ID[N],sum[N],T;

double ans;

int cmp(int x,int y)
{
        return sum[x]<sum[y];
}

int main()
{
        scanf("%d%d",&n,&T);
        for (i=1;i<=n;++i) 
        {
                scanf("%d",&a[i]);
        }
        for (i=1;i<=n;++i) scanf("%d",&t[i]);
        for (i=1;i<=n;++i)
        {
                if (t[i]==T) ans+=a[i];
                else if (t[i]<T) id[++id[0]]=i,sum[i]=T-t[i];
                else ID[++ID[0]]=i,sum[i]=t[i]-T;
        }
        sort(id+1,id+id[0]+1,cmp);
        sort(ID+1,ID+ID[0]+1,cmp);
        long long suma=0,sumb=0;
        for (i=1;i<=id[0];++i)
            suma+=1ll*sum[id[i]]*a[id[i]];
        for (i=1;i<=ID[0];++i)
            sumb+=1ll*sum[ID[i]]*a[ID[i]];
        if (suma<sumb)
        {
                swap(suma,sumb);
                for (i=0;i<=n;++i) swap(ID[i],id[i]);
        }
        for (i=1;i<=ID[0];++i) ans+=a[ID[i]];
        for (i=1;i<=id[0];++i)
            if (1ll*sum[id[i]]*a[id[i]]>=sumb)
            {
                    ans+=1.*sumb/sum[id[i]];
                    break;
            }
            else
            {
                    ans+=a[id[i]];
                    sumb-=1ll*sum[id[i]]*a[id[i]];
            }
        printf("%.10lf\n",ans);
}

 

 

 

 

 

 

 

 

 


 

 

 示例:

【代码】:

#include<bits/stdc++.h>

using namespace std;

int a[10000],n,m,l,r,mid,x;

int main()
{
    scanf("%d%d",&n,&x);
    
    for(int i=1;i<=n;++i)
      scanf("%d",&a[i]);
      
    sort(a+1,a+n+1);  //保证递增 
    
    int l=0,r=n+1,mid=0;  //初始化 
    
    while((l+r)>>1!=mid) //如果还可以继续二分 
    {
        mid=(l+r)>>1;
        if(x>=a[mid]) l=mid;
        else  r=mid;
    } 
    
    cout<<l;
    //找到x在序列中排第几 
}

 

 

 

 

 

      预处理相邻距离

      距离最远的那次尽可能短

      使用mid的跳跃是否合法

 

 【代码】:

#iclude<bits/stdc++.h> 

#define N 300005

using namespace std;

int i,j,m,n,p,k,a[N],x;

int check(int x)
{
        int i,cnt=0;
        for (i=1;i<=n;++i) if (a[i]-a[i-1]>x) return 0;  //跳不过去 
        for (i=0;i<n;)
        {
                for (j=i;j<=n&&a[j]-a[i]<=x;++j);
                ++cnt;
                i=j-1;
        }
        if (cnt<=m) return 1;
        return 0;
}

int main()
{
        scanf("%d%d",&n,&m);
        for (i=1;i<=n;++i) scanf("%d",&a[i]);
        sort(a+1,a+n+1);
        int l=0,r=(int)1e9,mid=0;    //因为没有给定右端点 
        while ((l+r)>>1!=mid)
        {
               mid=(l+r)>>1;
               if (check(mid)) r=mid;
               else l=mid;
        }
        printf("%d\n",r);
}

 

P2678 跳石头   

这也是个二分题,好像和刚才的不大一样

 

 

 

 

所以应该是:

 

 

 

 

#include<cstdio>
#include<algorithm>
#include<cstring>

#define N 300005

using namespace std;

int a[N],t[N],i,j,m,n,p,k,id[N],ID[N],sum[N],T;

double ans;

int cmp(int x,int y)
{
        return sum[x]<sum[y];
}

int main()
{
        scanf("%d%d",&n,&T);
        for (i=1;i<=n;++i) 
            scanf("%d",&a[i]);
           
        for (i=1;i<=n;++i) scanf("%d",&t[i]);
        for (i=1;i<=n;++i)
        {
                if (t[i]==T) ans+=a[i];
                else if (t[i]<T) id[++id[0]]=i,sum[i]=T-t[i];
                else ID[++ID[0]]=i,sum[i]=t[i]-T;
        }
        sort(id+1,id+id[0]+1,cmp);
        sort(ID+1,ID+ID[0]+1,cmp);
        long long suma=0,sumb=0;
        for (i=1;i<=id[0];++i)
            suma+=1ll*sum[id[i]]*a[id[i]];
        for (i=1;i<=ID[0];++i)
            sumb+=1ll*sum[ID[i]]*a[ID[i]];
        if (suma<sumb)
        {
                swap(suma,sumb);
                for (i=0;i<=n;++i) swap(ID[i],id[i]);
        }
        for (i=1;i<=ID[0];++i) ans+=a[ID[i]];
        for (i=1;i<=id[0];++i)
            if (1ll*sum[id[i]]*a[id[i]]>=sumb)
            {
                    ans+=1.*sumb/sum[id[i]];
                    break;
            }
            else
            {
                    ans+=a[id[i]];
                    sumb-=1ll*sum[id[i]]*a[id[i]];
            }
        printf("%.10lf\n",ans);
}

 

 

 

 

 

 

 

 

 

 【代码】

#include<bits/stdc++.h> 

#define N 500005

using namespace std;

int i,j,m,n,p,k,a[N],ty,x;

long long b[N];   //表示前K个数的前缀和 

double check(int x)   //平均数 
{
        return 1.*(b[x-1]+a[n])/x;
}

int main()
{
        scanf("%d",&m);
        for (;m--;)
        {
                scanf("%d",&ty);  //操作名称 
                
                if (ty==1)   //插入数的操作 
                {
                        scanf("%d",&x);
                        a[++n]=x;
                        b[n]=b[n-1]+x;
                }
                
                else
                {
                        int l=1,r=n;
                        while (r-l>10)   //保留一个尽量大的小三分区间,比如只有10个数 
                        {
                            int len=(r-l+1)/3,mid1=l+len,mid2=mid1+len; //三分,每次缩小三分之一 
                            if (check(mid1)<check(mid2)) r=mid2;   //因为函数图像是倒着的 
                            else l=mid1;
                        }
                        
                        //在区间内部枚举一下 
                        double ans=0;
                        for (i=l;i<=r;++i) ans=max(ans,a[n]-check(i));
                        printf("%.10lf\n",ans);
                }
                
        }
}

 

 


 

 

 

 

 

 

 

                

 

 

                    

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2019-04-29 07:49  晔子  阅读(265)  评论(0编辑  收藏  举报