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分!可见暴力骗分的强大!
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; }
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
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; }
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; }
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; }