http://codevs.cn/problem/1803/
根据题目范围可以想到直接搜索骗分,期望得分30分,实际得分30分,代码长度62行,写代码时间20分钟
#include
#include
#include
#include
#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
#include
#include
#include
#include
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 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->cc;
}
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分!可见暴力骗分的强大!
http://codevs.cn/problem/3290/
根据题目范围,80%数据的q<=10,出题者很明显给我们留好了退路:正解写不出来就暴力。
暴力做法:纯BFS+判重,期望得分80分,实际得分70分(可能是非官方数据更紧的缘故,实际上NOIP 2013时wjk神犇同一做法得到了85分)
#include
#include
#include
#include
#include
#include
#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;
queueq;
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
#include
#include
#include
#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];
}
};
queueq; //保存状态的bfs队列
priority_queue,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]>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]>ex>>ey>>sx>>sy>>tx>>ty;
if(sx==tx&&sy==ty) //不合法情况1:初始棋子位置和目标位置一样
{
cout<<0<
http://codevs.cn/problem/2818/
暴力做法:BFS建图+kruscal最小生成树,期望得分60分,实际得分66分
#include
#include
#include
#include
#include
#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_queueq;
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
正确解法:状压DP
http://codevs.cn/problem/3311
暴力做法:直接枚举,期望得分30分,实际得分30分
#include
#include
#include
#include
#include
#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
#include
#include
#include
#include
#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<=0;i--)
{
if((1<
http://codevs.cn/problem/3314
暴力做法:DFS乱搞,得分10分
#include
#include
#include
#include
#include
#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
正确解法:Link Cut Tree(代码来源: http://hzwer.com/3845.html)
#include
#include
#include
#include
#include
#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.aval[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
http://codevs.cn/problem/1135/
暴力思路:for循环枚举,最差复杂度O(n^3),最好复杂度O(1),期望得分50分,实际得分60分,代码长度38行,写代码时间20分钟
#include
#include
#include
#include
#include
#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
#include
#include
#include
#include
#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
#include
#include
#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]