模拟,搜索,暴力练习

10.21——————————————————————————————————————————————————————————————————————————-———

1.P1387 油滴扩展

/*
枚举一个判断一个。 
注意油滴半径不能为负数 
*/
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>

#define pi 3.1415926535897932384

using namespace std;
int x[7],y[7],bx,by,sx,sy;
int n;
bool vis[7];
double r[7],ans;

double dis(int i,int j)
{
    double xx1=x[i],xx2=x[j];
    double yy1=y[i],yy2=y[j];
    return sqrt((xx1-xx2)*(xx1-xx2)+(yy1-yy2)*(yy1-yy2));
}

double count(int i)
{
    return pi*r[i]*r[i];
}

void dfs(int cnt,double sum)
{
    if(cnt==n)
    {
        ans=max(ans,sum);
        return;
    }
    for(int i=1; i<=n; i++)
    {
        if(!vis[i])
        {
            vis[i]=1;
            r[i]=min(min(abs(x[i]-sx),abs(y[i]-sy)),min(abs(x[i]-bx),abs(y[i]-by)));
            for(int j=1; j<=n; j++)
            {
                if(i==j)continue;
                if(vis[j])r[i]=max(0.0,min(r[i],dis(i,j)-r[j]));
            }
            dfs(cnt+1,sum+count(i));
            vis[i]=0;
            r[i]=0;
        }
    }
}

int main()
{
    scanf("%d",&n);
    int a,b,c,d;
    scanf("%d%d%d%d",&a,&b,&c,&d);
    sx=min(a,c);sy=min(b,d);
    bx=max(a,c);by=max(b,d);
    for(int i=1; i<=n; i++)scanf("%d%d",&x[i],&y[i]);
    dfs(0,0);
    ans=(bx-sx)*(by-sy)-ans;
    printf("%.0lf",ans);
}
AC

 2.P1278单词游戏

#include<bits/stdc++.h>

#define N 101

using namespace std;
int n,m,ans,cnt;
bool vis[N];
struct node{
    int s,t,len;
}word[N];

void dfs(int tot,int Last,int rest)
{
    if(rest+tot<=ans) return;
    ans=max(ans,tot);
    for(int i=1;i<=n;i++)
    {
        if(vis[i] || (word[i].s!=word[Last].t&&Last)) continue;
        vis[i]=1;rest-=word[i].len;
        dfs(tot+word[i].len,i,rest);
        vis[i]=0;rest+=word[i].len;
    }
}

int main()
{
    static char s[N];int len;
    scanf("%d",&n);int sum=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%s",s+1);
        len=strlen(s+1);
        word[i].s=s[1];    word[i].t=s[len];
        word[i].len=len;sum+=word[i].len;
    }
    dfs(0,0,sum);
    printf("%d\n",ans);
    return 0;
} 
70分暴搜

 3.P1171售货员的难题

#include<bits/stdc++.h>

#define N 21
#define inf 0x3f3f3f3f

using namespace std;
int n,m,ans,cnt,mn;
int dis[N][N],vis[N];

inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}

void dfs(int now,int tot,int sum)
{
    if(sum>=ans)return;
    if(sum+(n-tot+1)*mn>=ans) return;
    for(int i=1;i<=n;i++)
    {
        if(tot==n && i==1)
        {
            ans=min(ans,sum+dis[now][i]);
            return;
        }
        if(i==now) continue;
        if(vis[i]) continue;
        vis[i]=1;
        dfs(i,tot+1,sum+dis[now][i]);
        vis[i]=0;
    }
}

int main()
{
    n=read();mn=inf;
    for(int i=1;i<=n;i++) for(int j=1;j<=n;j++)
    {
        dis[i][j]=read();
        if(i!=j) mn=min(mn,dis[i][j]);
    }
    ans=inf;vis[1]=1;dfs(1,1,0);
    printf("%d\n",ans);
    return 0;
}
90暴搜剪枝

10.22————————————————————————————————————————————————————————————————————————————————

 4.P2845 Switching on the Lights开关灯

/*
  一个房间可以走多次!可以另外写了一个bfs
*/
#include<bits/stdc++.h> 

#define N 110

using namespace std;
int n,m,e[4][2]= {{0,1},{0,-1},{-1,0},{1,0}};
int vis[N][N],bri[N][N],hav[N][N],v[N][N];
struct node{
    int x,y;
} cur,nxt,Map[N][N][10000];

node make_node(int x,int y)
{
    node res;res.x=x;res.y=y;
    return res;
}
queue<node>q;

void BFS()
{
    queue<node>que;
    while(!que.empty())que.pop();
    memset(v,0,sizeof(v));
    que.push(make_node(1,1));
    v[1][1]=1;
    while(!que.empty())
    {
        cur=que.front();
        que.pop();
        for(int i=0; i<4; i++)
        {
            int xx=e[i][0]+cur.x,yy=e[i][1]+cur.y;
            if(xx>n||xx<1||yy>n||yy<1)continue;
            if(!v[xx][yy]&&bri[xx][yy])
            {
                v[xx][yy]=1;
                que.push(make_node(xx,yy));
                if(!vis[xx][yy])
                    q.push(make_node(xx,yy)),vis[xx][yy]=1;
            }
        }
    }
}

void bfs()
{
    cur=make_node(1,1);
    vis[1][1]=1;bri[1][1]=1;
    q.push(cur);
    while(!q.empty())
    {
        while(!q.empty())
        {
            cur=q.front();
            q.pop();
            if(hav[cur.x][cur.y])
            {
                for(int i=1; i<=Map[cur.x][cur.y][0].x; i++)
                {
                    int tx=Map[cur.x][cur.y][i].x,ty=Map[cur.x][cur.y][i].y;
                    if(bri[tx][ty])continue;
                    bri[tx][ty]=1;
                }
            }
            for(int i=0; i<4; i++)
            {
                int xx=cur.x+e[i][0],yy=cur.y+e[i][1];
                if(xx<1||xx>n||yy<1||yy>n)continue;
                if(vis[xx][yy]||bri[xx][yy]==0)continue;
                q.push(make_node(xx,yy));
                vis[xx][yy]=1;
            }
        }
        BFS();
    }
}


int main()
{
    scanf("%d%d",&n,&m);
    int a,b,c,d;
    for(int i=1; i<=m; i++)
    {
        scanf("%d%d%d%d",&a,&b,&c,&d);
        Map[a][b][++Map[a][b][0].x].x=c;
        Map[a][b][Map[a][b][0].x].y=d;
        hav[a][b]=1;
    }
    bfs();
    int cnt=0;
    for(int i=1; i<=n; i++) for(int j=1; j<=n; j++)
      if(bri[i][j])cnt++;
    printf("%d",cnt);
}
myl太强啦

 5.P1930亚瑟王的宫殿

#include<bits/stdc++.h>

#define N 61
#define M 1007
#define inf 0x3f3f3f3f

using namespace std;
char ch[11];
int n,m,ans,cnt,xx,yy,step;
int dis[N][N][N][N],vis[M][M];
int e[8][2]={{1,2},{2,1},{-1,2},{2,-1},{1,-2},{-2,1},{-2,-1},{-1,-2}};
struct node{
    int x,y;
}k,u,q[M];    
queue<node>que;
inline node make_node(int x,int y){
    node res;res.x=x;res.y=y;
    return res;
}

inline int abs(int a)
{
    return a<0?-a:a;
}

inline bool judge(int x,int y)
{
    return (x>0&&x<=n&&y>0&&y<=m);
}

void bfs(int x,int y)
{
    memset(vis,0,sizeof vis);
    vis[x][y]=1;step=dis[x][y][x][y]=0;
    que.push(make_node(x,y));
    
    while(!que.empty())
    {
        u=que.front();que.pop();
        step=dis[x][y][u.x][u.y];
        for(int i=0;i<8;i++)
        {
            xx=u.x+e[i][0];yy=u.y+e[i][1];
            if(judge(xx,yy) && !vis[xx][yy])
            {
                vis[xx][yy]=1;dis[x][y][xx][yy]=step+1;
                que.push(make_node(xx,yy));            
            } 
        }
    }
}

void calculate_distance()
{
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
    for(int a=1;a<=n;a++) for(int b=1;b<=m;b++)
    dis[i][j][a][b]=inf;
    
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
    bfs(i,j);
}

void calculate_step()
{
    int flag,res=0,tmp=0;ans=inf;
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
    {
        flag=1;res=0;
        for(int a=1;a<=cnt;a++)
          if(dis[q[a].x][q[a].y][i][j]!=inf) res+=dis[q[a].x][q[a].y][i][j];
          else{flag=0;break;}
        if(!flag) continue;
        ans=min(ans,res+abs(k.x-i)+abs(k.y-j));
        
        for(int a=1;a<=cnt;a++)
        {
            tmp=res-dis[q[a].x][q[a].y][i][j];
            if(tmp>=ans) continue;
            for(int r=k.x-2;r<=k.x+2;r++) for(int c=k.y-2;c<=k.y+2;c++)
            {
                if(judge(r,c))
                ans=min(ans,tmp+dis[r][c][i][j]+dis[r][c][q[a].x][q[a].y]+abs(k.x-r)+abs(k.y-c));
            }
        }
    }
}

int main()
{
    freopen("ly.in","r",stdin);
    scanf("%d%d",&n,&m);
    scanf("%s%d",ch,&k.x);k.y=ch[0]-'A'+1;
    while(~scanf("%s%d",&ch,&q[++cnt].x)) q[cnt].y=ch[0]-'A'+1;
    
    calculate_distance();
    calculate_step();
    printf("%d\n",ans);
    return 0;
}
昨天T今天A?!

 6.P1037产生数

#include<bits/stdc++.h>

#define N 31 
#define mod 2333333

using namespace std;
int n,m,ans,cnt;
int rule[N][N],num[N],vis[3000000];
char s[N];
string s1;

void dfs()
{
    int T=1;
    for(int i=1;i<=n;i++) T=T*33+num[i],T%=mod;
    if(vis[T]) return;    vis[T]=1;
    ans++;
    for(int i=1;i<=n;i++) 
    {
        for(int j=0;j<=9;j++)
        {
            if(!rule[num[i]][j]) continue;
            int tmp=num[i];num[i]=j;
            dfs();num[i]=tmp;
        }
    }
}

int main()
{
//    freopen("ly.in","r",stdin);
    int x,y;
    scanf("%s%d",s+1,&m);n=strlen(s+1);
    for(int i=1;i<=n;i++) num[i]=s[i]-'0';
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        rule[x][y]=1;
    }
    ans=0;dfs();
    printf("%d\n",ans);
    return 0;
}
40暴搜哈希

7.P1294高手去散步

#include<bits/stdc++.h>

#define N 51

using namespace std;
int n,m,ans,cnt,res;
int head[N],vis[N];
struct edge{
    int u,v,w,nxt;
}e[N<<1];

inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}

inline void add(int u,int v,int w)
{
    e[++cnt].v=v;e[cnt].nxt=head[u];e[cnt].w=w;head[u]=cnt;
}

void dfs(int u,int sum)
{
    ans=max(ans,sum);
    for(int i=head[u];i;i=e[i].nxt)
    {
        int v=e[i].v;
        if(vis[v]) continue;
        vis[v]=1;dfs(v,sum+e[i].w);
        vis[v]=0;
    }return;
}

int main()
{
    int x,y,z;
    n=read();m=read();
    for(int i=1;i<=m;i++)
    {
        x=read();y=read();z=read();
        add(x,y,z);add(y,x,z);
    }
    
    for(int i=1;i<=n;i++)
    {
        memset(vis,0,sizeof vis);
        vis[i]=1;dfs(i,0);
    } 
    printf("%d\n",ans);
    return 0;
}
回溯..

8.P1363幻想迷宫  CF196B

/*
如果一个图能从起点到达无穷远,一定能从图的任意一点到达下一张图与原图对应的点
如何判断这个点是否能再次到达是关键
可以记录取模的横纵坐标x, y,记录没有取模的坐标lx,ly
开始遍历这个迷宫x,y一定分别等于lx,ly 
继续无限遍历下去如果一个点被访问过了但它的x,y不等于lx,ly则一定被再次走过。 
*/
#include<bits/stdc++.h>

#define N 1501

using namespace std;
int n,m,ans,cnt,sx,sy,flag;
int vis[N][N][3],a[N][N];
int dx[4]={1,-1,0,0};
int dy[4]={0,0,1,-1};

void dfs(int x,int y,int lx,int ly)
{
    if(flag) return;
    if((vis[x][y][1]!=lx || vis[x][y][2]!=y) && vis[x][y][0])
    {
        flag=1;return;
    }
    vis[x][y][1]=lx;vis[x][y][2]=ly;vis[x][y][0]=1;
    for(int i=0;i<4;i++)
    {
        int xx=(x+dx[i]+n)%n,yy=(y+dy[i]+m)%m;
        int lxx=lx+dx[i],lyy=ly+dy[i];
        if(a[xx][yy]) continue;
        if(!vis[xx][yy][0] || vis[xx][yy][1]!=lxx || vis[xx][yy][2]!=lyy)
        dfs(xx,yy,lxx,lyy);
    }
}

int main()
{
    char ch;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        flag=0;
        memset(vis,0,sizeof vis);
        memset(a,0,sizeof a);
        for(int i=0;i<n;i++) for(int j=0;j<m;j++)
        {
            cin>>ch;
            if(ch=='#') a[i][j]=1;
            else if(ch=='S') sx=i,sy=j;
        }
        dfs(sx,sy,sx,sy);
        if(flag) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
} 
好题

 10.23————————————————————————————————————————————————————————————————————————————————

9.P2329 栅栏 (P1523切蛋糕)

/*
二分答案
暴搜+剪枝 
*/
#include<bits/stdc++.h>

#define N 1011
#define inf 0x3f3f3f3f

using namespace std;
int n,m,ans,cnt,tmp,tot,waste,mid;
int len[N],a[N],vis[N];
int sum[N],cur[N];

inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}

inline int cmp(int a,int b){return a>b;}

bool dfs(int lim,int now)
{
    if(!lim) return true;
    if(tot-waste<sum[mid]) return 0;
    for(int i=now;i<=n;i++)
    {
        if(len[i]>=a[lim])
        {
            len[i]-=a[lim];
            if(len[i]<a[1])waste+=len[i];
            if(a[lim]==a[lim-1])
            {
                if(dfs(lim-1,i))return true;
            } 
            else if(dfs(lim-1,1)) return true;
            if(len[i]<a[1])waste-=len[i];
            len[i]+=a[lim];
        }
    }
    return false;
}

int main()
{
    n=read();
    for(int i=1;i<=n;i++) 
    len[i]=read(),tot+=len[i];
    m=read();
    for(int i=1;i<=m;i++) a[i]=read();
    sort(a+1,a+m+1);
    for(int i=1;i<=m;i++) sum[i]=sum[i-1]+a[i];
    for(int i=1;i<=n;i++) cur[i]=len[i];
    while(tot<a[m])m--;
    int l=1,r=m;
    while(l<=r)
    {
        waste=0;
        for(int i=1;i<=n;i++) len[i]=cur[i];
        mid=(l+r)>>1;
        if(dfs(mid,1)) ans=mid,l=mid+1;
        else r=mid-1;
    }
    printf("%d\n",ans);
    return 0;
}
这个搜索比较迷..

10.P2052 道路修建

/*
O(n) dfs预处理 
*/
#include<bits/stdc++.h>

#define N 1000007
#define ll long long

using namespace std;
ll n,m,ans,cnt;
ll head[N],son[N],deep[N];
struct edge{
    ll u,v,nxt,w;
}e[N<<1];

inline ll read()
{
    ll x=0,f=1;char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}

inline void add(ll u,ll v,ll w)
{
    e[++cnt].v=v;e[cnt].nxt=head[u];e[cnt].w=w;head[u]=cnt;
}

inline int abs(int a){return a<0?-a:a;}

void dfs(int u,int from,int c)
{
    son[u]=1;deep[u]=c;
    for(int i=head[u];i;i=e[i].nxt)
    {
        int v=e[i].v;
        if(v==from) continue;
        dfs(v,u,c+1);son[u]+=son[v];
    }
}

void Dfs(int u,int from)
{
    for(int i=head[u];i;i=e[i].nxt)
    {
        int v=e[i].v;
        if(v==from) continue;
        if(deep[v]>deep[u])
            ans+=abs(n-son[v]*2)*e[i].w;
        else ans+=abs(n-son[u]*2)*e[i].w;
        Dfs(v,u);
    }
}

int main()
{
    freopen("ly.in","r",stdin);
    ll x,y,z;
    n=read();
    for(int i=1;i<n;i++) 
    {
        x=read();y=read();z=read();
        add(x,y,z);add(y,x,z);
    }
    dfs(1,1,0);Dfs(1,1);
//    printf("%lld\n",ans);
    cout<<ans<<endl;
    return 0;
}
NOI2011......

10.25————————————————————————————————————————————————————————————————————————————————

11 codevs1108 方块游戏

/*
模拟题要在写之前构思好
代码的简洁性很重要!!
所以一定要想更好的办法把代码写简单。 
*/
#include <bits/stdc++.h>

#define mod 1000000007
#define N 101

using namespace std;
int n,m,t,flag;
int f[N][N],vis[N][N];
char a[N][N];

void dfs(int x,int y)
{

    if(y>m)x++,y=1;
    if(x>n) return;
    if(a[x][y]!=' ')
    {
        if(a[x][y]==a[x+1][y] && a[x][y]==a[x+2][y])
        {
            vis[x][y]=vis[x+1][y]=vis[x+2][y]=1;
            flag=1;
        }
        if(a[x][y]==a[x][y+1] && a[x][y]==a[x][y+2])
        {
            vis[x][y]=vis[x][y+1]=vis[x][y+2]=1;
            flag=1;
        }
        if(a[x][y]==a[x+1][y+1] && a[x][y]==a[x+2][y+2])
        {
            vis[x][y]=vis[x+1][y+1]=vis[x+2][y+2]=1;
            flag=1;
        }
        if(a[x][y]==a[x+1][y-1] && a[x][y]==a[x+2][y-2])
        {
            vis[x][y]=vis[x+1][y-1]=vis[x+2][y-2]=1;
            flag=1;
        }
    }
    dfs(x,y+1);
}

int main()
{
    cin>>n>>m;
    for(int i=1; i<=n; i++) cin>>a[i]+1;
    while(1)
    {
        flag=0;
        memset(vis,0,sizeof(vis));
        dfs(1,1);
        if(flag==0) break;
        for(int j=1; j<=m; j++)
        {
            int k=n;
            for(int i=n; i>=1; i--)
            {
                char p=a[i][j]; a[i][j]=' ';
                if(vis[i][j]==0)a[k--][j]=p;
            }
        }
    }
    for(int i=1; i<=n; i++) cout<<a[i]+1<<endl;
    return 0;
}
唉,人生啊

12.P2484打地鼠

#include<bits/stdc++.h>

#define N 107
#define inf 0x3f3f3f3f

using namespace std;
int g[N][N],a[N][N];
int n,m,sum;

bool check(int r,int c)//判断r*c是否可行
{
    if((sum%(r*c)))return false;//可行性剪枝
    else
    {
        for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
        a[i][j]=g[i][j];
        for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
        if(a[i][j])
        {
            int t=a[i][j];
            for(int q=1;q<=r;q++) for(int w=1;w<=c;w++)
            {
                if(i+q-1>n||j+w-1>m)return false;
                a[i+q-1][j+w-1]-=t;
                if(a[i+q-1][j+w-1]<0)
                return false;
            }
        }
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        if(a[i][j])return false;
        return true;
    }
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
    scanf("%d",&g[i][j]),sum+=g[i][j];
    int ans=inf;
    for(int r=1;r<=n;r++) for(int c=1;c<=m;c++)
    if(check(r,c))
      ans=min(ans,(sum)/(r*c));
    cout<<ans<<endl;
    return 0;
}
暴搜+剪枝
/*
我好蠢啊 
20暴力
*/
#include<bits/stdc++.h>

#define inf 0x3f3f3f3f
#define N 1001

using namespace std;
int n,m,ans,cnt,opt;
int num[N][N],tmp[N][N];

inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}

bool judge()
{
    for(int i=1;i<=n;i++) 
      for(int j=1;j<=m;j++)
        if(num[i][j]!=0) return false;
    return true;
}

void dfs(int x,int y,int r,int c)
{
    if(opt) return;
    if(cnt>=ans) {opt=1;return;}
    if(judge()){ans=min(ans,cnt);opt=1;return;}
    if(y==m+1 ||y+c-1>m) y=1,x++;
    if(x+r-1>n)return;
    int flag=0;
    for(int i=x;i<x+r;i++) for(int j=y;j<y+c;j++)
    if(!num[i][j]){flag=1;break;}
    if(flag) dfs(x,y+1,r,c);
    else
    {
        for(int i=x;i<x+r;i++) for(int j=y;j<y+c;j++)
        num[i][j]--;cnt++;
        dfs(x,y,r,c);
    } dfs(x,y+1,r,c);
}

int main()
{
    m=read();n=read();swap(n,m);
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
    num[i][j]=tmp[i][j]=read();
    ans=inf;
    for(int r=1;r<=n;r++) for(int c=1;c<=m;c++)
    {
        opt=0;cnt=0;
        for(int a=1;a<=n;a++) for(int b=1;b<=m;b++)
        num[a][b]=tmp[a][b];
        dfs(1,1,r,c);
    }
    printf("%d\n",ans);
    return 0;
} 
我是智障

10.28——————————————————————————————————————————————————————————————————————————————

13.bzoj1620Time Management 

#include<bits/stdc++.h>

#define N 1001

using namespace std;
int n,m,ans,cnt;
struct node{
    int s,t;
    
    bool operator < (const node &a) const{
            return t<a.t;
    }
    
}p[N];

inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}

int main()
{
    n=read();ans=0x3f3f3f3f;
    for(int i=1;i<=n;i++) p[i].s=read(),p[i].t=read();
    sort(p+1,p+n+1);int now=0,flag=0;
    for(int i=1;i<=n;i++)
    {
        if(now+p[i].s>p[i].t) {flag=1;break;}
        now+=p[i].s;ans=min(ans,p[i].t-now);
    }
    if(flag){printf("-1\n");return 0;}
    else printf("%d\n",ans);
    return 0;
}
1A

10.30————————————————————————————————————————————————————————————————————————————————

14 bzoj1770 [Usaco2009 Nov]lights 燈    (P2962)

#include<bits/stdc++.h>

#define N 40
#define mod 2333333
#define M 500

using namespace std;
int n,m,ans,cnt,opt,s;
int head[M<<1],vis[N],V[2333337],light[N];
struct edge{
    int u,v,nxt;
}e[M<<1];

inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

inline void add(int u,int v)
{
    e[++cnt].v=v;e[cnt].nxt=head[u];head[u]=cnt;
}

bool judge(int u)
{
    for(int i=1;i<=n;i++) if(!light[i]) return false;
    return true;
}

int get()
{
    int ss=1;
    for(int i=1;i<=n;i++) 
    {
        ss+=ss*33+(light[i]+1)%mod;
        ss%=mod;
    }
    return ss;
}

void dfs(int u,int tot)
{
    if(ans<=tot) return;
    if(judge(1))
    {
        ans=min(ans,tot);
        return;
    }
    for(int i=head[u];i;i=e[i].nxt)
    {
        int v=e[i].v;
        if(vis[v]) continue;vis[v]=1;
        dfs(v,tot);    
        
        vis[v]=0;light[v]^=1;
        for(int j=head[v];j;j=e[j].nxt) light[e[j].v]^=1;
        s=get();
        if(V[s]) continue;V[s]=1;
        dfs(v,tot+1);
    }
}

int main()
{
    int x,y;
    n=read();m=read();
    for(int i=1;i<=m;i++)
    {
        x=read();y=read();
        add(x,y);add(y,x);
    }ans=0x3f3f3f3f;
    
    for(int i=head[1];i;i=e[i].nxt) light[e[i].v]^=1;
    vis[1]=1;light[1]^=1;dfs(1,1);
    memset(vis,0,sizeof vis);
    memset(light,0,sizeof light);
    memset(V,0,sizeof V);
    vis[1]=1; dfs(1,0);
    printf("%d\n",ans);
    return 0;
}
10分蜜汁wa
/*
折半搜索经典题
注意每个点随时都可以去。
搜一半,map记录这一半所有状态的最小步数。
搜另一半时,用当前状态步数+记录好的当前补集步数即可。 
*/
#include<bits/stdc++.h>

#define inf 1000000000
#define N 40
#define ll long long

using namespace std;
int n,m,cnt,ans=inf;
int a[N];
bool flag;
ll ed,p[N],bin[N];
map<ll,int>step;

inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

void dfs(int x,ll sta,int tot)//sta是当前状态,ed是末状态 
{
    if(x==cnt+1)
    {
        if(sta==ed)ans=min(tot,ans);
        if(!flag)
        {
            int t=step[sta];
            if(!t || t>tot)step[sta]=tot;
        }
        else
        {
            int t=step[ed-sta];//取记录好的当前状态的补集 
            if(!t)return;
            ans=min(t+tot,ans);
        }
        return;
    }
    dfs(x+1,sta,tot);
    dfs(x+1,sta^p[x],tot+1);
}

int main()
{
    bin[1]=1;for(int i=2;i<40;i++)bin[i]=bin[i-1]<<1;
    n=read();m=read();
    ed=bin[n+1]-1;
    for(int i=1;i<=m;i++)
    {
        int a=read(),b=read();
        p[a]|=bin[b];p[b]|=bin[a];//记录每个点能改变那些点的状态 
    }
    for(int i=1;i<=n;i++)p[i]+=bin[i];//也能改变当前点的状态 
    cnt=n/2;dfs(1,0,0);
    flag=1;
    cnt=n;dfs(n/2+1,0,0);
    printf("%d\n",ans);
    return 0;
}
折半搜索

15.P2921 [USACO08DEC]在农场万圣节Trick or Treat on the Farm

#include<bits/stdc++.h>

#define N 100007

using namespace std;
int n,m,ans,cnt,num,tot;
int head[N],Head[N],dfn[N],low[N],scc[N],bel[N];
int V[N],A[N];
bool in_st[N],vis[N];
stack<int>st;
struct edge{
    int u,v,nxt;
}e[N<<1],E[N<<1];

inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

inline void add(int u,int v)
{
    e[++cnt].v=v;e[cnt].nxt=head[u];head[u]=cnt;
}

inline void add_(int u,int v)
{
    E[++cnt].v=v;E[cnt].nxt=Head[u];Head[u]=cnt;
}

void Tarjan(int u)
{
    dfn[u]=low[u]=++cnt;
    st.push(u);in_st[u]=1;
    for(int i=head[u];i;i=e[i].nxt)
    {
        int v=e[i].v;
        if(!dfn[v])
            Tarjan(v),low[u]=min(low[u],low[v]);
        else if(in_st[v])
            low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u])
    {
        num++;tot=0;
        while(st.top()!=u)
        {
            tot++;
            bel[st.top()]=num;
            in_st[st.top()]=0;st.pop();
        }
        tot++;
        bel[st.top()]=num;scc[num]=tot;
        in_st[st.top()]=0;st.pop();
    }
}

void dfs(int u,int sum)
{
    if(V[u]) {ans+=A[u];return;}
    ans=sum;
    for(int i=Head[u];i;i=E[i].nxt)
    {
        int v=E[i].v;
        if(vis[v]) continue;
        vis[v]=1;dfs(v,sum+scc[v]);
    }
}

int main()
{
    int x;
    n=read();
    for(int i=1;i<=n;i++)
    {
        x=read();add(i,x);
    }
    cnt=0;
    for(int i=1;i<=n;i++) if(!dfn[i]) Tarjan(i);
    cnt=0;
    for(int i=1;i<=n;i++) for(int j=head[i];j;j=e[j].nxt)
        if(bel[i]!=bel[e[j].v]) add_(bel[i],bel[e[j].v]);
        
    for(int i=1;i<=n;i++)
    {    
        ans=0;memset(vis,0,sizeof vis);
        if(!V[bel[i]])
        {
            vis[bel[i]]=1,dfs(bel[i],scc[bel[i]]),A[bel[i]]=ans,V[bel[i]]=1;
        }
        else ans=A[bel[i]];
        printf("%d\n",ans);
    }
    return 0;
}
记忆化搜索

10.31————————————————————————————————————————————————————————————————————————————————

16.bzoj4506: [Usaco2016 Jan]Fort Moo(暴力)

/*
预处理每个点能往上下左右扩展的距离
n^2枚举每个点n^2暴力扩展
复杂度n^4
emmm 加点优化就过了 
*/
#include<bits/stdc++.h>

#define N 201

using namespace std;
int n,m,ans,cnt;
int a[N][N];
int ex_up[N][N],ex_down[N][N],ex_L[N][N],ex_R[N][N];
char ch;

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
    {
        cin>>ch;
        a[i][j]=(ch=='.'?0:1);
    }
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
    {
        cnt=0;
        while(j+cnt<=m && !a[i][j+cnt]) cnt++;
        if(cnt) ex_R[i][j]=cnt-1;
        cnt=0;
        while(j-cnt>=1 && !a[i][j-cnt]) cnt++;
        if(cnt) ex_L[i][j]=cnt-1;
        cnt=0;
        while(i-cnt>=1 && !a[i-cnt][j]) cnt++;
        if(cnt) ex_up[i][j]=cnt-1;
        cnt=0;
        while(i+cnt<=n && !a[i+cnt][j]) cnt++;
        if(cnt) ex_down[i][j]=cnt-1;
    }
    ans=1;
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
    {
        if(!ex_R[i][j]) continue;
        if((ex_R[i][j]+1)*(ex_down[i][j]+1)<=ans) continue;
        for(int x=j;x<=j+ex_R[i][j];x++)
        {
            if(!ex_down[i][x]) continue;
            for(int y=i;y<=i+ex_down[i][j];y++)
            {
                if(i+ex_down[i][x]>n || j+ex_R[y][j]>m) continue;
                if(i+ex_down[i][x]>=y && j+ex_R[y][j]>=x) ans=max(ans,(x-j+1)*(y-i+1));
            }
        } 
    }
    printf("%d\n",ans);
    return 0;
}
暴力枚举+优化

11.1——————————————————————————————————————————————————————————————————————————————————

17.bzoj2679: [Usaco2012 Open]Balanced Cow Subsets

 #include<bits/stdc++.h>
 
 #define N 30
 #define M 3111111
 #define mod 2333333
 
 using namespace std;
 int n,m,ans,cnt,flag;
 int a[N],vis[N],V[M];
 int cur[N],sum[N];
 
 inline int read()
 {
     int x=0,f=1;char c=getchar();
     while(c>'9'||c<'0'){if(x=='-')f=-1;c=getchar();}
     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
     return x*f;
 }
 
 /*bool dfs2(int cur[],int k,int val,int n)
 {
     if(n==2 && cur[1]!=cur[2]) return false;  
     if(flag) return true;
     if(val==sum[n]-val) {flag=1;return true;}
     if(k==n && !flag) return false;
     for(int i=k+1;i<=n;i++)
     dfs2(cur,i,val+cur[i],n),dfs2(cur,i,val,n);
     if(!flag)return false;
 }*/
 
 bool judge()
 {
     int cnt_=0,S=1;
     static int dp[N][M];
     memset(dp,0,sizeof dp);
     memset(cur,0,sizeof cur);
    memset(sum,0,sizeof sum);
     for(int i=1;i<=n;i++) if(vis[i]) cur[++cnt_]=a[i],sum[cnt_]=sum[cnt_-1]+cur[cnt_];
     sort(cur+1,cur+cnt_+1);
     for(int i=1;i<=cnt_;i++) S+=S*33+cur[i],S%=mod;
     if(V[S]) return false;V[S]=1;flag=0;
     if(sum[cnt_]%2) return false;
    if(cnt_==2 && cur[1]!=cur[2]) return false;   
    
     for(int i=0;i<=cnt_;i++) dp[i][cur[i]]=dp[i][0]=1;
     for(int i=1;i<=cnt_;i++) for(int j=1;j<=sum[cnt_];j++)
     {
         if(j>=cur[i-1])
           dp[i][j]=(dp[i-1][j] || dp[i-1][j-cur[i]]);
         else dp[i][j]=dp[i-1][j];
    }
     return (dp[cnt_][sum[cnt_]/2]);
 }
 
 void dfs(int lim,int k,int tot)
 {
     if(tot==lim)
     {
         if(judge()) ans++;
         return;
    }
     if(k>n) return;
     for(int i=k+1;i<=n;i++)
     {
         if(vis[i]) continue;
         vis[i]=1;dfs(lim,k+1,tot+1);
         vis[i]=0;
    }
 }
 
 int main()
 {
    freopen("ly.in","r",stdin);
     n=read();
     for(int i=1;i<=n;i++) a[i]=read();
     cnt=2;
    while(cnt<=n)
    {
        memset(vis,0,sizeof vis);
        dfs(cnt,0,0);
        cnt++;
    }
    printf("%d\n",ans);
    return 0;
 }
24暴搜
/*
折半搜索
枚举每个数如何选择,放入A就加,放入B就减 
状压判断每个数的具体选择状态
最后双指针扫统计答案  若集合A的和 + 集合B的和为0那么就说明这两个集合构成的答案合法 
*/
#include<bits/stdc++.h>

#define N 22
#define ll long long

using namespace std;
int n,v[N<<1],maxdep,cnta,cntb;
bool vis[1<<N];
ll ans;
struct node{    
    int state,x;
}a[1<<N],b[1<<N];
inline bool cmp1(node a,node b){return a.x<b.x;}
inline bool cmp2(node a,node b){return a.x>b.x;}

inline int read()
 {
     int x=0,f=1;char c=getchar();
     while(c>'9'||c<'0'){if(x=='-')f=-1;c=getchar();}
     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
     return x*f;
 }

void dfs(int dep,int sum,int now,int flag)
{
    if(dep==maxdep+1)
    {
        if(!flag)
            a[++cnta].x=sum,a[cnta].state=now;
        else
            b[++cntb].x=sum,b[cntb].state=now;
        return;
    }
    dfs(dep+1,sum,now,flag);
    dfs(dep+1,sum+v[dep],now | (1<<(dep-1)),flag);
    dfs(dep+1,sum-v[dep],now | (1<<(dep-1)),flag);
}
int main()
{
    n=read();
    for(int i=1; i<=n; i++)v[i]=read();
    maxdep=n/2;dfs(1,0,0,0);
    maxdep=n;  dfs(n/2+1,0,0,1);
    sort(a+1,a+1+cnta,cmp1);
    sort(b+1,b+1+cntb,cmp2);
    
    int l=1,r=1;
    while(l<=cnta&&r<=cntb)
    {
        while(-a[l].x<b[r].x&&r<=cntb)r++;
        int pos=r;
        while(r<=cntb&&-a[l].x==b[r].x)
        {
            if(!vis[a[l].state | b[r].state])
            {
                vis[a[l].state | b[r].state]=1;
                ans++;
            }r++;
        }
        if(l<cnta&&a[l].x==a[l+1].x)r=pos;
        l++;
    }
    printf("%lld\n",ans-1);//减去空集 
    return 0;
}
折半搜索

18.4800: [Ceoi2015]Ice Hockey World Championship(折半搜索)

#include<bits/stdc++.h>

#define N 45
#define M 1000007
#define ll long long

using namespace std;
ll n,m,ans,cnt,mx,flag;
ll val[N],f[N][M];

inline ll read()
 {
     ll x=0,f=1;char c=getchar();
     while(c>'9'||c<'0'){if(x=='-')f=-1;c=getchar();}
     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
     return x*f;
 }

void dfs(int k,ll sum)
{
    if(sum>m) return;
    if(k==n)
    {
        ans++;return;
    }
    dfs(k+1,sum);
    dfs(k+1,sum+val[k+1]);
}

void dp()
{
    f[0][m]=1;
    for(int i=1;i<=n;i++) for(int j=0;j<=m;j++)
    {
        f[i][j]+=f[i-1][j]+f[i-1][j+val[i]];
    }
    for(int i=0;i<=m;i++) ans+=f[n][i];
}

int main()
{
    //freopen("ly.in","r",stdin);
    n=read();m=read();
    for(int i=1;i<=n;i++) val[i]=read();
    if(m<=1e6) dp();
    else dfs(0,0);
    printf("%lld\n",ans);
    return 0;
} 
80 dfs+dp
/*
折半搜索 
*/
#include<bits/stdc++.h>

#define ll long long
#define N 55

using namespace std;
ll n,m,mid,cnta,cntb,ans;
ll w[N],suma[1<<21],sumb[1<<21];

inline ll read()
 {
     ll x=0,f=1;char c=getchar();
     while(c>'9'||c<'0'){if(x=='-')f=-1;c=getchar();}
     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
     return x*f;
 }

inline void dfs(int l,int r,ll sum,ll a[],ll &cnt)
{
    if(sum>m)return;
    if(l>r)
    {
        a[++cnt]=sum;return;
    }
    dfs(l+1,r,sum+w[l],a,cnt);
    dfs(l+1,r,sum,a,cnt);
}

int main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++)w[i]=read();;
    mid=n/2;
    dfs(1,mid,0,suma,cnta);
    dfs(mid+1,n,0,sumb,cntb);
    sort(suma+1,suma+1+cnta);
    for(int i=1; i<=cntb; i++)
        ans+=upper_bound(suma+1,suma+1+cnta,m-sumb[i])-suma-1;
    printf("%lld\n",ans);
    return 0;
}
折半搜索

19.P2210 Haywire

#include<bits/stdc++.h>

#define N 20

using namespace std;
int n,m,ans,cnt;
int a[N],vis[N],dis[N][N],fri[N][4];

inline int read()
 {
     int x=0,f=1;char c=getchar();
     while(c>'9'||c<'0'){if(x=='-')f=-1;c=getchar();}
     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
     return x*f;
 }

inline int abs_(int a){return a<0?-a:a;}

void calc()
{
    static int pos[N];
    for(int i=1;i<=n;i++) pos[a[i]]=i; 
    int tot=0;memset(dis,0,sizeof dis);
    for(int i=1;i<=n;i++) for(int j=1;j<=3;j++)
    {
        if(dis[i][fri[i][j]] || dis[fri[i][j]][i]) continue; 
        dis[i][fri[i][j]]=dis[fri[i][j]][i]=1;tot+=abs_(pos[i]-pos[fri[i][j]]);
    }ans=min(ans,tot);
}

void dfs(int k)
{
    for(int i=1;i<=n;i++)
    {
        if(!vis[i])
        {
             vis[i]=1;a[k]=i;
            if(k==n) calc();
            dfs(k+1);
            vis[i]=0;
        }    
    }
}

int main()
{
    //freopen("ly.in","r",stdin); 
    n=read();
    for(int i=1;i<=n;i++) for(int j=1;j<=3;j++)
    fri[i][j]=read();
    ans=0x3f3f3f3f;dfs(1);
    printf("%d\n",ans);
    return 0;
}
49暴搜
/*
nowtot:当前总距离; 
links:已经访问的所有奶牛中,有多少路线没有找到,(即某奶牛的朋友还没有找到); 
remain:已经访问的所有奶牛中,没有找到的路线的长度总和,(是当前,并不是所有);
因为每条路线至少是1,所以我们假定所有没找到的路线开始都为1;

每次,remain+links,即当前位置,还没有找到的所有路线都+1(显然); 
因此remain是我们的方案的下限,即最小的估值(不可能更小了);

其实,这只是个“随机”值,但这个随机值不会让答案错误; 
*/
#include<bits/stdc++.h>

#define N 20

using namespace std;

int fr[N][5],a[N],pos[N];
int n,ans,cnt;
bool vis[N];

void dfs(int x,int nowtot,int links,int remain)
{

    if(x==n+1) ans=min(ans,nowtot);
    if(remain+nowtot >= ans) return;//最优化剪枝

    for(int i=1;i<=n;i++)
    {
        if(!pos[i])
        {
            int new_link=3,sum=0;//每个奶牛开始有三个朋友;
            pos[i]=x;//第i个奶牛放在x上; 
            for(int j=1;j<=3;j++)
            {
                if(pos[fr[i][j]]!=0)
                {
                    sum+=abs(x-pos[fr[i][j]]);//发现这条路线已经确定;
                    new_link-=2;//friend路线-1,当前奶牛同样-1,总的减2; 
                }
            }
            dfs(x+1,nowtot+sum,links+new_link,remain+(links+new_link)-sum);
            pos[i]=0;
        }
    }
    return;
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)for(int j=1;j<=3;j++)
    scanf("%d",&fr[i][j]);
    ans=0x3f3f3f3f; dfs(1,0,0,0);
    printf("%d\n",ans);
    return 0;
}
A*

20.codeforces 1006 F. Xor-Paths

/*
暴搜2^(n+m)
折半搜索 
*/
#include<bits/stdc++.h>

#define N 27
#define ll long long

using namespace std;
ll n,m,k,ans,flag;
ll a[N][N];
map<ll,ll>M[N][N];

inline ll read()
{
     ll x=0,f=1;char c=getchar();
     while(c>'9'||c<'0'){if(x=='-')f=-1;c=getchar();}
     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
     return x*f;
}

void dfs(int dep,int x,int y,ll sta)
{
    if(x<1 || x>n || y<1 || y>m) return;
    if(!flag) sta^=a[x][y];
    if(x+y==dep)
    {
        if(!flag){M[x][y][sta]++;return;}
        else{ans+=M[x][y][k^sta];return;}
    }
    if(!flag){
        dfs(dep,x+1,y,sta);dfs(dep,x,y+1,sta);
    }
    else{
        sta^=a[x][y];
        dfs(dep,x-1,y,sta);dfs(dep,x,y-1,sta);
    }
}

int main()
{
    n=read();m=read();k=read();
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
    a[i][j]=read();
    flag=0;dfs((n+m+2)/2,1,1,0);
    flag=1;dfs((n+m+2)/2,n,m,0);
    printf("%lld\n",ans);
    return 0;
}
折半搜索

 11.2————————————————————————————————————————————————————————————————————————————————

21.codeforces 880E. Maximum Subsequence(折半搜索+双指针)

/*
折半搜索,把取模后的和存起来 
双指针统计答案 
*/
#include<bits/stdc++.h>

#define N 300000

using namespace std;
int a[N],p[N],q[N];
int k,t,ans,n,m,b,dep,flag;

inline int max(int x,int y){return x>y? x:y;}

inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}

void dfs(int now,int sum)
{
    if(now==dep)
    {
        if(!flag)
        {
            p[++k]=sum,p[++k]=(sum+a[b])%m;return;
        }
        else
        {
            q[++t]=sum,q[++t]=(sum+a[n])%m;
            return ;
        }
    }
    dfs(now+1,sum);
    dfs(now+1,(sum+a[now])%m);
}

int main()
{
    n=read(),m=read(),b=n>>1;dep=b;
    for(int i=1; i<=n; ++i) a[i]=read();
    if(n==1) printf("%d",a[1]%m),exit(0);
    flag=0;dfs(1,0);
    dep=n;flag=1;dfs(b+1,0);
    int L=0,R=t;
    sort(p+1,p+k+1);sort(q+1,q+t+1);
    while(L<=k)
    {
        while(p[L]+q[R]>=m) --R;
        ans=max(ans,p[L]+q[R]),++L;
    }
    ans=max(ans,p[k]+q[t]-m);
    printf("%d",ans);
    return 0;
}
折半搜索

 11.4—————————————————————————————————————————————————————————————————————————————————

22.codeforces912E(折半搜索+双指针+二分答案)

/*
直接枚举判断显然不可以。 
考虑折半搜索。可以把这16个数字拆成2个子集,各自生成所有大小1e18及以下的积。 
但也需要使两个乘积组成的集合尽量接近。可以预先造出极限数据试一试集合里能有多少数 
对于最坏情况,即如下数据
16
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53
分为2 3 5 7 11 13 和  17 19 23 29 31 37 41 43 47 53 两个集合时
这两个集合生成的1e18及以下的积的数量分别为 958460个 和 505756个,并不大 
集合中数必须两两不等。
最后统计答案, 
两个集合生成的积各自排一下序
然后二分答案,对于每个答案 u,可以O(|S|)双指针得到他是第几大。
具体做法是枚举从到小枚举第一个集合的积 t1,然后计算一下第二个集合的积中有多少积和 t1 相乘小于等于 u,
由于是从大到小枚举的,所以t1必然递增所以第二个集合的积中符合条件的积的数量也必然是递增的,所以只要扫一遍就行。 
*/
#include<bits/stdc++.h>

#define ll long long
#define inf 1e18
#define N 24

using namespace std; 
vector<ll> seg[2];
int p[N],n;
ll ansid;
 
void dfs(int L,int R,ll val,int id)
{
    seg[id].push_back(val);
    for(int i=L;i<=R;i++)
      if(inf/p[i]>=val) dfs(i,R,val*p[i],id);
}
 
ll cnt(ll num)
{
    int j=0;
    ll ret=0;
    for(int i=seg[0].size()-1;i>=0;i--)
    {
        while(j<seg[1].size() && seg[1][j]<=num/seg[0][i])
            j++;
        ret+=j;
    }
    return ret;
}
 
void solve()
{
    int i,j;
    dfs(1,min(6,n),1,0);
    dfs(min(6,n)+1,n,1,1);
    sort(seg[0].begin(),seg[0].end());
    sort(seg[1].begin(),seg[1].end());
    ll L=0,R=inf,mid;
    while(L<R-1)
    {
        mid=(L+R)>>1;
        if(cnt(mid)>=ansid) R=mid;
        else L=mid;
    }
    cout<<R<<endl;
}
 
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&p[i]);
    cin>>ansid;
    solve();
    return 0;
}
折半搜索

23.bzoj1048(记忆化搜索)

#include<bits/stdc++.h>
#define inf 1000000000
#define ll long long
using namespace std;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int n,m,K;
double ave;
int a[15][15];
int s[15][15];
double t[15][15][15][15][15];

double dfs(int a,int b,int c,int d,int k)
{
    double &res=t[a][b][c][d][k];
    if(res!=-1)return res;
    if(k==0)
    {
        res=s[b][d]+s[a-1][c-1]-s[a-1][d]-s[b][c-1];
        res=(res-ave)*(res-ave);
        return res;
    }
    res=1e9;
    for(int i=a+1;i<=b;i++)
        for(int j=0;j<k;j++)
            res=min(res,dfs(a,i-1,c,d,j)+dfs(i,b,c,d,k-j-1));
    for(int i=c+1;i<=d;i++)
        for(int j=0;j<k;j++)
            res=min(res,dfs(a,b,c,i-1,j)+dfs(a,b,i,d,k-j-1));
    return res;
}

int main()
{
    n=read();m=read();K=read();
    for(int a=0;a<=10;a++) for(int b=0;b<=10;b++)
    for(int c=0;c<=10;c++) for(int d=0;d<=10;d++)
        for(int l=0;l<=10;l++)
          t[a][b][c][d][l]=-1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            a[i][j]=read();
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j],
    ave=(double)s[n][m]/K;
    dfs(1,n,1,m,K-1);
    printf("%.2lf",sqrt(t[1][n][1][m][K-1]/K));
    return 0;    
}
记忆化搜索

11.8—————————————————————————————————————————————————————————————————————————————————

#include<bits/stdc++.h>

#define N 51
#define inf 0x3f3f3f3f
#define eps 0.00001

using namespace std;
int n,m,T,ans,cnt[10000000],flag,dfn;
double x[N],y[N],a,b;
int died[N],vis[N][N];
int d[N][N],cur[1000000][51];

void calc(int i,int j)//算a,b 
{
    flag=0;
    double x1=x[i],x2=x[j],y1=y[i],y2=y[j];
    if(x1==x2) {a=0,b=x1;return;}
    b=(x2*x2*y1-x1*x1*y2)/(x1*x2*x2-x1*x1*x2);
    a=(y1-b*x1)/(x1*x1);
}

void work(double a,double b,int dfn)
{
    cnt[dfn]=0;
    for(int i=1;i<=n;i++)
    {
        if(died[i]) continue;
        if(a*x[i]*x[i]+b*x[i]+eps>=y[i] && a*x[i]*x[i]+b*x[i]-eps<=y[i]) 
        died[i]=1,cnt[dfn]++,cur[dfn][cnt[dfn]]=i;//cur记录这只鸟打掉的猪 
    }
}

void dfs(int use,int rest,int dfn)//用了多少鸟,剩下多少猪 
{

/*    int d_bug=0;
    for(int i=1;i<=n;i++) if(died[i]) d_bug++;
    if(n-rest!=d_bug)
    {
        cout<<use<<" "<<rest<<endl;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            cout<<vis[i][j]<<" ";
            printf("\n");
        } 
        cout<<endl;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            cout<<d[i][j]<<" ";
            printf("\n");
        } cout<<endl;
        for(int i=1;i<=n;i++) cout<<died[i]<<" ";
        cout<<endl;
        for(int i=1;i<=dfn;i++) 
        {
            for(int j=1;j<=cnt[dfn];j++)
            cout<<cur[i][j]<<" ";
            cout<<endl;
        }
        cout<<endl;
        exit(0);
        
    }
    */
    if(use>=ans) return;
    if(m==1 && use>n/3+1) return;//剪枝 
    if(rest==0)
    {
        ans=min(ans,use);
        return;
    }
    for(int i=1;i<=n;i++)
    {
        if(died[i]) continue;
        for(int j=i+1;j<=n;j++)
        {
            if(died[j]) continue;
            if(vis[i][j] || vis[j][i] || d[i][j] || d[j][i]) continue;
            calc(i,j);//算抛物线 
            if(a>=0){d[i][j]=d[j][i]=1;continue;}//d数组为了剪枝;a<0时,i,j一定不能组成需要的抛物线 
            work(a,b,dfn);//算这条抛物线能打掉多少 
            vis[i][j]=vis[j][i]=1;//标记这条抛物线 
            dfs(use+1,rest-cnt[dfn],dfn+1);
            for(int k=1;k<=cnt[dfn];k++) died[cur[dfn][k]]=0;//把这条抛物线打掉的复活 
            vis[i][j]=vis[j][i]=0;//memset(cur,0,sizeof cur);
        }
        if(!died[i]) died[i]=1,dfs(use+1,rest-1,dfn+1),died[i]=0;//没有点跟i组成抛物线,单独一条。 
    }
}

void clear()
{
    memset(died,0,sizeof died);
    memset(d,0,sizeof d);
    memset(vis,0,sizeof vis);
}

int main()
{
    scanf("%d",&T);
    while(T--)
    {
        clear();
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        scanf("%lf%lf",&x[i],&y[i]);
        ans=inf;dfs(0,n,1);
        printf("%d\n",ans);
    }
    return 0;
}
60dfs

 25 bzoj1725: [Usaco2006 Nov]Corn Fields牧场的安排(状压dfs)

/*
我才不要写状压dp呢!! 
状压dfs
对于每一行dfs一次。顺便记录这一行的状态能否对下一行的状态产生贡献。
*/
#include<bits/stdc++.h>

#define N 100000
#define S 30
#define mod 100000000

using namespace std;
int m,n,ans;
int f[S][N],a[S];

inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}

void dfs(int x,int y,int sta,int nxt)//nxt是下行状态 
{
    if(y>=n)
    {
        f[x+1][nxt]+=f[x][sta];
        f[x+1][nxt]%=mod;
        return;
    }
    dfs(x,y+1,sta,nxt);//不放 
    if(!(sta&(1<<y))) dfs(x,y+2,sta,nxt|(1<<y));//保证左右,和下面不相邻 
}

int main()
{
    int x;
    m=read();n=read();
    for(int i=1;i<=m;i++) for(int j=0;j<n;j++)
    {
        x=read();
        if(x==0) a[i]=a[i]|(1<<j);
    }f[1][a[1]]=1;//初始,第一行,不放,方案数为1 

    for(int i=1;i<=m;i++) for(int j=a[i];j<(1<<n);j++)
      if(f[i][j]) dfs(i,0,j,a[i+1]);//如果当前航这个状态合法,就从这个状态dfs 
    for(int i=0;i<(1<<n);i++)
    ans+=f[m+1][i],ans%=mod;
    printf("%d\n",ans);
    return 0;
}
状压dfs

 

posted @ 2018-10-20 19:46  安月冷  阅读(285)  评论(0编辑  收藏  举报