关于暴力&瞎搞骗分的一些实例

骗分的实质:不会做的题用最少的时间写代码得到最多的分数

下面是几个乱搞骗分的实例,抛砖引玉让大家感受下骗分的强大:

1、NOI 2008 志愿者招募

http://codevs.cn/problem/1803/

根据题目范围可以想到直接搜索骗分,期望得分30分,实际得分30分,代码长度62行,写代码时间20分钟

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>

#define MAXN 1100
#define INF 0x3f3f3f3f

using namespace std;

struct info
{
    int s,t,c,id;
}infos[MAXN];

int n,m;
bool used[MAXN];
int minCost;
int a[MAXN];
int ans=INF;

void dfs(int x,int cost) //到第x种志愿者花费为cost
{
    if(x>m)
    {
        for(int i=1;i<=n;i++)
            if(a[i]>0)
                return;
        if(ans>cost) ans=cost;
        return;
    }
    dfs(x+1,cost);
    int L=infos[x].s,R=infos[x].t;
    int minNeed=0;
    for(int i=L;i<=R;i++)
    {
        if(a[i]>minNeed) minNeed=a[i];
    }
    for(int need=1;need<=minNeed;need++)
    {
        for(int i=L;i<=R;i++)
            a[i]-=need;
        dfs(x+1,cost+infos[x].c*need);
        for(int i=L;i<=R;i++)
            a[i]+=need;
    }

}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&infos[i].s,&infos[i].t,&infos[i].c);
    }
    dfs(1,0);
    printf("%d\n",ans);
    return 0;
}

正确做法:图论、网络流,代码长度: (代码来源:https://www.byvoid.com/blog/noi-2008-employee/)

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
const int MAXN=1003,MAXM=10002*4,INF=0x7FFFFFFF;
using namespace std;
struct edge
{
    edge *next,*op;
    int t,c,v;
}ES[MAXM],*V[MAXN];
struct Queue
{
    int Q[MAXN],QH,QL,Size;
    bool inq[MAXN];
    inline void ins(int v)
    {
        if (++QL>=MAXN)
            QL=0;
        Q[QL]=v;
        inq[v]=true;
        Size++;
    }
    inline int pop()
    {
        int r=Q[QH];
        inq[r]=false;
        Size--;
        if (++QH>=MAXN)
            QH=0;
        return r;
    }
    inline void reset()
    {
        memset(Q,0,sizeof(Q));
        QH=Size=0;
        QL=-1;
    }
}Q;
int N,M,S,T,EC=-1;
int demond[MAXN],sp[MAXN],prev[MAXN];
edge *path[MAXN];
inline void addedge(int a,int b,int v,int c=INF)
{
    edge e1={V[a],0,b,c,v} , e2={V[b],0,a,0,-v};
    ES[++EC]=e1; V[a]=&ES[EC];
    ES[++EC]=e2; V[b]=&ES[EC];
    V[a]->op=V[b]; V[b]->op=V[a];
}
void init()
{
    int i,a,b,c;
    freopen("employee.in","r",stdin);
    freopen("employee.out","w",stdout);
    scanf("%d%d",&N,&M);
    for (i=1;i<=N;i++)
        scanf("%d",&demond[i]);
    for (i=1;i<=M;i++)
    {
        scanf("%d%d%d",&a,&b,&c);
        addedge(a,b+1,c);
    }
    S=0,T=N+2;
    for (i=1;i<=N+1;i++)
    {
        c = demond[i] - demond[i-1];
        if (c>=0)
            addedge(S,i,0,c);
        else
            addedge(i,T,0,-c);
        if (i>1)
            addedge(i,i-1,0);
    }
}
bool spfa()
{
    int u,v;
    for (u=S;u<=T;u++)
        sp[u]=INF;
    Q.reset();
    Q.ins(S);
    sp[S]=0;
    prev[S]=-1;
    while (Q.Size)
    {
        u=Q.pop();
        for (edge *k=V[u];k;k=k->next)
        {
            v=k->t;
            if (k->c>0 && sp[u] + k->v <sp[v])
            {
                sp[v]=sp[u] + k->v;
                prev[v]=u;
                path[v]=k;
                if (!Q.inq[v])
                    Q.ins(v);
            }
        }
    }
    return sp[T]!=INF;
}
int argument()
{
    int i,delta=INF,flow=0;
    edge *e;
    for (i=T;prev[i]!=-1;i=prev[i])
    {
        e=path[i];
        if (e->c<delta)
            delta=e->c;
    }
    for (i=T;prev[i]!=-1;i=prev[i])
    {
        e=path[i];
        e->c-=delta;e->op->c+=delta;
        flow+=e->v*delta;
    }
    return flow;
}
int maxcostflow()
{
    int Flow=0;
    while (spfa())
        Flow += argument();
    return Flow;
}
int main()
{
    init();
    printf("%dn",maxcostflow());
    return 0;
}
NOI时此题平均得分只有12.56分!可见暴力骗分的强大!

2、NOIP 2013 华容道

http://codevs.cn/problem/3290/

根据题目范围,80%数据的q<=10,出题者很明显给我们留好了退路:正解写不出来就暴力。

暴力做法:纯BFS+判重,期望得分80分,实际得分70分(可能是非官方数据更紧的缘故,实际上NOIP 2013时wjk神犇同一做法得到了85分)

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <queue>

#define MAXN 33

using namespace std;

bool visit[MAXN][MAXN][MAXN][MAXN];
int map[MAXN][MAXN];

struct node
{
    int bx,by,x,y; //绿色棋子为(x,y),空白格子为(bx,by)
    int step;
}first;

queue<node>q;

int xx[]={1,-1,0,0},yy[]={0,0,1,-1};
int ex,ey,sx,sy,tx,ty;
int n,m,Q;

bool inMap(int bx,int by,int x,int y)
{
    if(bx==x&&by==y) return false;
    if(bx<1||bx>n||by<1||by>m) return false;
    if(map[bx][by]) return false;
    if(x<1||x>n||y<1||y>m) return false;
    if(map[x][y]) return false;
    return true;
}

int bfs()
{
    while(!q.empty()) q.pop();
    q.push(first);
    visit[first.bx][first.by][first.x][first.y]=true;
    while(!q.empty())
    {
        node now=q.front();
        q.pop();
        if(now.x==tx&&now.y==ty) return now.step;
        if(abs(now.bx-now.x)+abs(now.by-now.y)==1) //棋子与空格相邻
        {
            node next=now;
            next.step++;
            swap(next.x,next.bx);
            swap(next.y,next.by);
            if(inMap(next.bx,next.by,next.x,next.y)&&!visit[next.bx][next.by][next.x][next.y])
            {
                visit[next.bx][next.by][next.x][next.y]=true;
                q.push(next);
            }
        }
        for(int dir=0;dir<4;dir++) //白格移动方向
        {
            node next=now;
            next.step++;
            next.bx+=xx[dir],next.by+=yy[dir];
            if(inMap(next.bx,next.by,next.x,next.y)&&!visit[next.bx][next.by][next.x][next.y])
            {
                visit[next.bx][next.by][next.x][next.y]=true;
                q.push(next);
            }
        }
    }
    return -1;
}

int main()
{
    scanf("%d%d%d",&n,&m,&Q);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&map[i][j]);
            map[i][j]=1-map[i][j];
        }
    for(int i=1;i<=Q;i++)
    {
        memset(visit,0,sizeof(visit));
        first.step=0;
        scanf("%d%d%d%d%d%d",&first.bx,&first.by,&first.x,&first.y,&tx,&ty);
        int ans=bfs();
        //if(ans>1000000) ans=-1;
        printf("%d\n",ans);
    }
    return 0;
}


正确解法:BFS建图+SPFA,非常复杂而且写起来容易错。

#include<iostream>
#include<cstdio>
#include<cstring>
#include <queue>

#define MAXN 32
#define MAXV 50010
#define INF (1<<26)

using namespace std;

int xx[]={1,-1,0,0},yy[]={0,0,1,-1};

struct edge
{
    edge *next; //上一条边的指针
    int t,w; //目标节点,边权
    edge()
    {
        next=NULL;
    }
}*head[MAXV];

struct node //保存棋子状态
{
    int x,y;
    node(int xx,int yy):x(xx),y(yy) {}
};

int map[MAXN][MAXN],n,m,Q,ex,ey,sx,sy,tx,ty; //空白格子(ex,ey),指定棋子(sx,sy),目标位置(tx,ty)
int v[MAXN][MAXN][4],dist[MAXN][MAXN],move[MAXN][MAXN][4][4];
int Dis[MAXV],S,T,V=0;
bool visit[MAXV];

struct cmp
{
    bool operator()(int x,int y)
    {
        return Dis[x]>Dis[y];
    }
};

queue<node>q; //保存状态的bfs队列
priority_queue<int,vector<int>,cmp>pq;

void AddEdge(int s,int t,int w) //建立有向边s->t,边权为w
{
    edge *p=new(edge); //新建一个边
    p->t=t;
    p->w=w;
    p->next=head[s];
    head[s]=p;
}

int bfs(int SX,int SY,int TX,int TY) //求出(SX,SY)到(TX,TY)的距离
{
    if(SX==TX&&SY==TY) return 0;
    while(!q.empty()) q.pop();
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            dist[i][j]=INF;
    dist[SX][SY]=0; //出发点到出发点费用为0
    q.push(node(SX,SY));
    while(!q.empty())
    {
        node now=q.front();
        q.pop(); //队首出队
        for(int i=0;i<4;i++)
        {
            if(map[now.x+xx[i]][now.y+yy[i]]&&dist[now.x+xx[i]][now.y+yy[i]]==INF) //移动后的点的距离没有被拓展过,且没有越界
            {
                dist[now.x+xx[i]][now.y+yy[i]]=dist[now.x][now.y]+1;
                if(now.x+xx[i]==TX&&now.y+yy[i]==TY) return dist[now.x][now.y]+1; //移动到了目标节点,返回距离
                q.push(node(now.x+xx[i],now.y+yy[i])); //新状态入队
            }
        }
    }
    return INF;
}

int spfa()
{
    for(int i=1;i<=V;i++) Dis[i]=INF;
    memset(visit,true,sizeof(visit));
    while(!pq.empty()) pq.pop();
    Dis[S]=0;
    pq.push(S);
    while(!pq.empty())
    {
        int now=pq.top();
        pq.pop();
        if(!visit[now]) continue;
        visit[now]=false;
        if(now==T) return Dis[T]; //求得了到达终点的距离,返回
        for(edge *p=head[now];p;p=p->next)
        {
            if(Dis[p->t]>Dis[now]+p->w) //有优化的空间
            {
                Dis[p->t]=Dis[now]+p->w;
                visit[p->t]=true;
                pq.push(p->t);
            }
        }
    }
    return Dis[T]<INF?Dis[T]:-1;
}

int main()
{
    cin>>n>>m>>Q;
    memset(map,0,sizeof(map));
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            cin>>map[i][j];
            for(int k=0;k<4;k++)
                v[i][j][k]=++V;
        }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            for(int k=0;k<4;k++)
                for(int h=0;h<4;h++)
                    move[i][j][k][h]=INF;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(map[i][j])
            {
                map[i][j]=0;
                for(int k=0;k<4;k++)
                {
                    if(map[i+xx[k]][j+yy[k]])
                    {
                        for(int h=0;h<4;h++)
                        {
                            if(map[i+xx[h]][j+yy[h]])
                            {
                                move[i][j][k][h]=bfs(i+xx[k],j+yy[k],i+xx[h],j+yy[h])+1;
                            }
                        }
                    }
                }
                map[i][j]=1;
            }
        }
    }
    memset(head,0,sizeof(head));
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            for(int k=0;k<4;k++)
                for(int h=0;h<4;h++)
                    if(move[i][j][k][h]<INF)
                        AddEdge(v[i][j][k],v[i+xx[h]][j+yy[h]][h^1],move[i][j][k][h]);
    while(Q--)
    {
        cin>>ex>>ey>>sx>>sy>>tx>>ty;
        if(sx==tx&&sy==ty) //不合法情况1:初始棋子位置和目标位置一样
        {
            cout<<0<<endl;
            continue;
        }
        S=++V; //新建一个起点
        T=++V; //新建一个终点
        if(map[sx][sy]==0||map[tx][ty]==0) //不合法情况2:初始位置或目标位置不能走,有障碍物
        {
            cout<<-1<<endl;
            continue;
        }
        map[sx][sy]=0;
        for(int i=0;i<4;i++)
        {
            if(map[sx+xx[i]][sy+yy[i]]) //该点为起点相邻的点,若该点可走
            {
                int D=bfs(ex,ey,sx+xx[i],sy+yy[i]); //求出它到空白格子之间的距离
                if(D<INF) //能走通
                    AddEdge(S,v[sx][sy][i],D); //在起点状态和图中的S点之间建边
            }
        }
        map[sx][sy]=1;
        for(int i=0;i<4;i++)
            if(map[tx+xx[i]][ty+yy[i]]) //该点为终点相邻的点,若该点可走
                AddEdge(v[tx][ty][i],T,0); //终点和图中T点建边,边权为0
        cout<<spfa()<<endl;
    }
    return 0;
}


3、Codevs 2818 为了信仰

http://codevs.cn/problem/2818/

暴力做法:BFS建图+kruscal最小生成树,期望得分60分,实际得分66分

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>

#define MAXN 110

using namespace std;

struct node
{
    int x,y,step;
    bool operator<(const node &b)const{return step>b.step;}
};

struct edge
{
    int u,v,w,next;
}edges[MAXN*MAXN];

priority_queue<node>q;

int head[MAXN],nCount=0;
int map[MAXN][MAXN];
int tmp[MAXN][MAXN];
int n,m,k;
int blackx[MAXN],blacky[MAXN];
bool visit[MAXN][MAXN];
int xx[]={1,-1,0,0},yy[]={0,0,1,-1};

void AddEdge(int U,int V,int W)
{
    edges[++nCount].u=U;
    edges[nCount].v=V;
    edges[nCount].w=W;
    edges[nCount].next=head[U];
    head[U]=nCount;
}

bool inMap(int x,int y)
{
    if(x<1||x>n||y<1||y>m) return false;
    return true;
}

int bfs(int sx,int sy,int tx,int ty)
{
    memset(visit,0,sizeof(visit));
    memcpy(tmp,map,sizeof(map));
    while(!q.empty()) q.pop();
    node first;
    first.step=0;
    first.x=sx,first.y=sy;
    visit[sx][sy]=true;
    q.push(first);
    while(!q.empty())
    {
        node now=q.top();
        q.pop();
        if(now.x==tx&&now.y==ty) return now.step;
        for(int dir=0;dir<4;dir++)
        {
            node next=now;
            next.x+=xx[dir],next.y+=yy[dir];
            if(!inMap(next.x,next.y)) continue;
            if(visit[next.x][next.y]) continue;
            if(!map[next.x][next.y])
                next.step++;
            visit[next.x][next.y]=true;
            q.push(next);
        }
    }
    memcpy(map,tmp,sizeof(tmp));
    return -1;
}

int f[MAXN];

int findSet(int x)
{
    if(f[x]==x) return f[x];
    return f[x]=findSet(f[x]);
}

bool cmp(edge a,edge b)
{
    return a.w<b.w;
}

int kruscal()
{
    int ans=0;
    sort(edges+1,edges+nCount+1,cmp);
    for(int i=1;i<=nCount;i++)
    {
        int rootu=findSet(edges[i].u),rootv=findSet(edges[i].v);
        if(rootu!=rootv)
        {
            ans+=edges[i].w;
            f[rootu]=rootv;
        }
    }
    return ans;
}

int main()
{
    char in[MAXN];
    for(int i=0;i<MAXN;i++) f[i]=i;
    memset(head,-1,sizeof(head));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",in+1);
        for(int j=1;j<=m;j++)
            map[i][j]=in[j]-'0';
    }
    scanf("%d",&k);
    for(int i=1;i<=k;i++)
    {
        scanf("%d%d",&blackx[i],&blacky[i]);
        blackx[i]++;
        blacky[i]++;
    }
    for(int i=1;i<=k;i++)
        for(int j=1;j<=k;j++)
            if(i<j)
            {
                if(blackx[i]==blackx[j]&&blacky[i]==blacky[j])
                {
                    AddEdge(i,j,0);
                    continue;
                }
                int w=bfs(blackx[i],blacky[i],blackx[j],blacky[j]);
                if(w!=-1) AddEdge(i,j,w);
            }
    printf("%d\n",kruscal());
    return 0;
}
正确解法:状压DP


4、NOI 2014 起床困难综合症

http://codevs.cn/problem/3311

暴力做法:直接枚举,期望得分30分,实际得分30分

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

#define MAXN 100100
#define INF 0x3f3f3f3f

using namespace std;

char op[MAXN];
int t[MAXN];
int ans=INF;
int n,m;

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        char cmd[10];
        scanf("%s%d",cmd,&t[i]);
        op[i]=cmd[0];
    }
    int maxAns=0,ans;
    for(int tmp=0;tmp<=m;tmp++)
    {
        ans=tmp;
        for(int i=1;i<=n;i++)
        {
            if(op[i]=='A')
                ans=ans&t[i];
            else if(op[i]=='O')
                ans=ans|t[i];
            else
                ans=ans^t[i];
        }
        if(ans>maxAns) maxAns=ans;
    }
    printf("%d\n",maxAns);
    return 0;
}

正确解法:二进制(代码来源:http://hzwer.com/3841.html)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
inline ll 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,a[100005],b[100005],f[35],ans,tot;
int cal(int x)
{
	for(int i=1;i<=n;i++)
		if(a[i]==1)x=(x&b[i]);
		else if(a[i]==2)x=(x|b[i]);
		else x=(x^b[i]);
	return x;
}
int main()
{
	//freopen("sleep.in","r",stdin);
	//freopen("sleep.out","w",stdout);
	n=read();m=read();
	for(int i=1;i<=n;i++)
	{
		char ch[5];
		scanf("%s",ch);
		if(ch[0]=='A')a[i]=1;
		else if(ch[0]=='O')a[i]=2;
		else a[i]=3;
		b[i]=read();
	}
	int t=cal(0);
	for(int i=0;i<=30;i++)f[i]=(cal(1<<i)&(1<<i));
    for(int i=30;i>=0;i--)
	{
		if((1<<i)&t)ans+=(1<<i);
		else if((tot+(1<<i)<=m)&&f[i])
		{
			tot+=f[i];
			ans+=f[i];
		}
	}
	printf("%d",ans);
	return 0;
}


5、NOI 2014 魔法森林

http://codevs.cn/problem/3314

暴力做法:DFS乱搞,得分10分

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

#define MAXV 1000010
#define MAXE 50100
#define INF 0x3f3f3f3f

using namespace std;

struct edge
{
    int u,v,a,b,next;
}edges[MAXV];

int head[MAXE],nCount=0;
bool visit[MAXE];
int maxa=0,maxb=0;
int n,m;

void AddEdge(int U,int V,int A,int B)
{
    edges[++nCount].u=U;
    edges[nCount].v=V;
    edges[nCount].a=A;
    edges[nCount].b=B;
    edges[nCount].next=head[U];
    head[U]=nCount;
}

int dfs(int u) //从点u下去dfs,找一个路上a和b总个数最大值最小的路
{
    int ans=INF;
    if(u==n) return maxa+maxb;
    visit[u]=true;
    for(int p=head[u];p!=-1;p=edges[p].next)
    {
        int v=edges[p].v;
        if(visit[v]) continue;
        int tmpa=maxa,tmpb=maxb;
        if(edges[p].a>maxa) maxa=edges[p].a;
        if(edges[p].b>maxb) maxb=edges[p].b;
        int tmp=dfs(v);
        if(tmp<ans) ans=tmp;
        maxa=tmpa,maxb=tmpb;
    }
    return ans;
}

int main()
{
    memset(head,-1,sizeof(head));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int x,y,a,b;
        scanf("%d%d%d%d",&x,&y,&a,&b);
        AddEdge(x,y,a,b);
        AddEdge(y,x,a,b);
    }
    printf("%d\n",dfs(1));
    return 0;
}
正确解法:Link Cut Tree(代码来源: http://hzwer.com/3845.html)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define inf 1000000000
using namespace std;
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;
}
int top,n,m,tot,ans=inf;
struct edge{int u,v,a,b;}e[100005];
int f[150005];
int c[150005][2],fa[150005];
int q[150005],val[150005],mx[150005];
bool rev[150005];
int find(int x)
{
	return x==f[x]?x:f[x]=find(f[x]);
}
bool operator<(edge a,edge b)
{
	return a.a<b.a;
}
bool isroot(int x)
{
	return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;
}
void update(int x)
{
	int l=c[x][0],r=c[x][1];
	mx[x]=x;
	if(val[mx[l]]>val[mx[x]])mx[x]=mx[l];
	if(val[mx[r]]>val[mx[x]])mx[x]=mx[r];
}
void pushdown(int x)
{
	int l=c[x][0],r=c[x][1];
	if(rev[x])
	{
		rev[x]^=1;rev[l]^=1;rev[r]^=1;
		swap(c[x][0],c[x][1]);
	}
}
void rotate(int x)
{
	int y=fa[x],z=fa[y],l,r;
	if(c[y][0]==x)l=0;else l=1;r=l^1;
	if(!isroot(y))
	{
		if(c[z][0]==y)c[z][0]=x;else c[z][1]=x;
	}
	fa[x]=z;fa[y]=x;fa[c[x][r]]=y;
	c[y][l]=c[x][r];c[x][r]=y;
	update(y);update(x);
}
void splay(int x)
{
	top=0;q[++top]=x;
	for(int i=x;!isroot(i);i=fa[i])
		q[++top]=fa[i];
	for(int i=top;i;i--)
		pushdown(q[i]);
	while(!isroot(x))
	{
		int y=fa[x],z=fa[y];
		if(!isroot(y))
		{
			if(c[y][0]==x^c[z][0]==y)rotate(x);
			else rotate(y);
		}
		rotate(x);
	}
	update(x);
}
void access(int x)
{
	int t=0;
	while(x)
	{
		splay(x);c[x][1]=t;t=x;x=fa[x];
	}
}
void makeroot(int x)
{
	access(x);splay(x);rev[x]^=1;
}
void link(int x,int y)
{
	makeroot(x);fa[x]=y;
}
void cut(int x,int y)
{
	makeroot(x);access(y);splay(y);c[y][0]=fa[x]=0;
}
int query(int x,int y)
{
	makeroot(x);access(y);splay(y);return mx[y];
}
void solve(int k)
{
	int u=e[k].u,v=e[k].v,w=e[k].b;
	int t=query(u,v);
	if(w<val[t])
	{	
		cut(e[t-n].u,t);cut(e[t-n].v,t);
		link(u,k+n);link(v,k+n);
	}
}
int main()
{
	n=read();m=read();
	for(int i=1;i<=n;i++)f[i]=i;
	for(int i=1;i<=m;i++)
	{
		e[i].u=read();e[i].v=read();e[i].a=read();e[i].b=read();
	}
	sort(e+1,e+m+1);
	for(int i=1;i<=m;i++)
	{
		val[n+i]=e[i].b;mx[n+i]=n+i;
	}
	for(int i=1;i<=m;i++)
	{
		int u=e[i].u,v=e[i].v,w=e[i].b;
		int p=find(u),q=find(v);
		if(p!=q)
		{
			f[p]=q;
			link(u,n+i);link(v,n+i);
		}
		else solve(i);
		if(find(1)==find(n))ans=min(ans,val[query(1,n)]+e[i].a);
	}
	if(ans!=inf)printf("%d\n",ans);
	else puts("-1");
	return 0;
}


5、Codevs 1135 选择客栈(NOIP 2011提高组)

http://codevs.cn/problem/1135/

暴力思路:for循环枚举,最差复杂度O(n^3),最好复杂度O(1),期望得分50分,实际得分60分,代码长度38行,写代码时间20分钟

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

#define MAXN 2000100
#define INF 0x3f3f3f3f

using namespace std;

int color[MAXN],cost[MAXN];

int main()
{
    int n,k,p,ans=0;
	scanf("%d%d%d",&n,&k,&p);
	for(int i=1;i<=n;i++)
		scanf("%d%d",&color[i],&cost[i]);
	for(int L=1;L<=n;L++)
		for(int R=L;R<=n;R++)
		{
		    if(R==L) continue;
			bool flag=false;
			if(color[L]==color[R])
			{
				for(int i=L;i<=R;i++)
				{
					if(cost[i]<=p)
						flag=true;
				}
			}
			if(flag)
				ans++;
		}
	printf("%d\n",ans);
    return 0;
}


加了前缀和优化后,节省了求和的那一维时间,最差复杂度变为O(n^2),但是得分还是60分,TLE的4个点数据太大了

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

#define MAXN 2000100
#define INF 0x3f3f3f3f

using namespace std;

int color[MAXN],cost[MAXN];
int sum[MAXN]; //sum[i]=前i个客栈<=p的个数

int main()
{
    int n,k,p,ans=0;
	scanf("%d%d%d",&n,&k,&p);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&color[i],&cost[i]);
		if(cost[i]<=p) sum[i]=sum[i-1]+1;
		else sum[i]=sum[i-1];
	}
	for(int L=1;L<=n;L++)
		for(int R=L;R<=n;R++)
		{
		    if(R==L) continue;
			bool flag=false;
			if(color[L]==color[R])
			{
				if(sum[R]-sum[L-1]>0) ans++;
			}
		}
	printf("%d\n",ans);
    return 0;
}


正确思路:动态规划,代码不是很长,但是不是很好想,而且容易错

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAXN 200100

int cheapMaxNum[MAXN],colorMaxNum[MAXN],sameColorNum[MAXN],ans[MAXN],colorNum[MAXN],maxNum[MAXN];

/*
	声明:便宜的客栈就是价格低于最高消费的客栈
	cheapMaxNum[i]=1~i中编号最大的便宜客栈
	colorMaxNum[i]=1~i-1中与i颜色相同的编号最大的客栈
	sameColorNum[i]=1~i-1中和i颜色相同的客栈个数
	ans[i]=1~i-1中与i颜色相同,且其到i之间有便宜客栈的个数
	DP方程为:
	ans[i]=ans[colorMaxNum[i]],cheapMaxNum[i]<=colorMaxNum[i]
	ans[i]=sameColorNum[i],cheapMaxNum[i]>colorMaxNum[i]
	colorNum[i]=之前所有客栈中色调为i的个数,maxNum[i]=之前所有客栈中色调为i的最大客栈编号
*/

int main()
{
	int n,k,p,color,price;
	scanf("%d%d%d",&n,&k,&p);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&color,&price);
		colorMaxNum[i]=maxNum[color]; //前i-1个客栈中与i相同颜色的客栈最大编号就是之前color色调的最大客栈编号
		sameColorNum[i]=colorNum[color]; //同理
		if(price<=p) //i号客栈是便宜客栈
			cheapMaxNum[i]=i; //前i个客栈中便宜客栈的最大编号就是i自己
		else cheapMaxNum[i]=cheapMaxNum[i-1]; //否则前i个客栈中便宜客栈最大编号和前i-1个的相同
		if(cheapMaxNum[i]<colorMaxNum[i])
			ans[i]=ans[colorMaxNum[i]];
		else
			ans[i]=sameColorNum[i];
		colorNum[color]++;
		maxNum[color]=i;
	}
	int Ans=0;
	for(int i=2;i<=n;i++) //找客栈尾巴,统计方案总个数
			Ans+=ans[i];
	printf("%d\n",Ans);
	return 0;
}















你可能感兴趣的:(关于暴力&瞎搞骗分的一些实例)