第一次AK掉div 2,非常开心,罚时也还好。
比赛中的提交记录
在正式和非正式选手中排名179名(共6932人)
在正式选手里排名27名(共2826人)
http://codeforces.com/contest/545/problem/A
给出每个车 i 和其他车 j 的碰撞情况( i 撞毁、 j 撞毁、 i、j 均撞毁、 i、j 均未撞毁),问有多少个车在和其他任意车碰撞后,都不会撞毁
水题,就不多说了
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <vector>
#define MAXN 110
using namespace std;
int mat[MAXN][MAXN],n;
int sol[MAXN],top=0;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&mat[i][j]);
for(int i=1;i<=n;i++)
{
bool flag=true;
for(int j=1;j<=n;j++)
if(mat[i][j]==1||mat[i][j]==3)
{
flag=false;
break;
}
if(flag) sol[++top]=i;
}
printf("%d\n",top);
if(!top) return 0;
for(int i=1;i<=top;i++)
printf("%d ",sol[i]);
printf("\n");
return 0;
}
http://codeforces.com/contest/545/problem/B
定义两个串 S 、 T 的差别度 diff(S,T) 为, S 和 T 中 Si≠Ti 的 i 的个数
要你构造一个串 A ,使得 diff(A,S)=diff(A,T)
水题,首先看 S 和 T 有多少位不相同,若不相同的位的个数 tot 为奇数则显然无解,否则构造一个串 A ,其中若 Si=Ti ,则 Ai=Si ,前 tot2 个 Si≠Ti 的位置填 Si ,后 tot2 个 Si≠Ti 的位置填 Ti
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <vector>
#define MAXN 110000
using namespace std;
char A[MAXN],B[MAXN];
int n;
int main()
{
scanf("%s",A+1);
scanf("%s",B+1);
n=strlen(A+1);
int tot=0;
for(int i=1;i<=n;i++)
if(A[i]!=B[i])
tot++;
if(tot&1)
{
printf("impossible\n");
return 0;
}
tot/=2;
for(int i=1,t=1;i<=n;i++)
{
if(A[i]==B[i]) printf("%c",A[i]);
else if(t<=tot) {printf("%c",A[i]); t++;}
else printf("%c",B[i]);
}
printf("\n");
return 0;
}
http://codeforces.com/contest/545/problem/C
一共有 n 个树,你要从第一个树一直砍到最后一个树。对于每个高度为 hi 、树根在 xi 的树,你可以选择拔除它,留下区间为 [xi,xi] 的坑,或者让它往左边倒,留下区间为 [xi−hi,xi] 的坑,或者让它往右边倒,留下区间为 [xi,xi+hi] 的坑,但是砍树的前提是,留下的新坑不能和以前任何一个老坑相交,问最多能让多少个树倒下而不是拔除。
第 i 个树能否倒下,取决于第 i−1 个树的状态,因此我们可以做 O(n) 的DP。用 f[i][0] 表示第 i 个树往左倒,最多能倒下的树的个数,用 f[i][1] 表示第 i 个树拔除掉,最多能倒下的树的个数,用 f[i][2] 表示第 i 个树往右倒,最多能倒下的树的个数
然后剩余要做的事就是各种特判了。
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <vector>
#define MAXN 110000
using namespace std;
typedef long long int LL;
int n;
LL h[MAXN],x[MAXN];
int f[MAXN][3];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%I64d%I64d",&x[i],&h[i]);
f[1][0]=f[1][1]=f[1][2]=1;
for(int i=2;i<=n;i++)
{
//往左倒
if(x[i]-h[i]>x[i-1]+h[i-1]) f[i][0]=max(f[i][0],f[i-1][2]+1);
if(x[i]-h[i]>x[i-1])
{
f[i][0]=max(f[i][0],f[i-1][1]);
f[i][0]=max(f[i][0],f[i-1][0]+1);
}
//拔出
if(x[i]>x[i-1]) f[i][1]=max(f[i][1],f[i-1][1]);
if(x[i]>x[i-1]+h[i-1]) f[i][1]=max(f[i][1],f[i-1][2]+1);
if(x[i]>x[i-1]) f[i][1]=max(f[i][1],f[i-1][0]+1);
//往右倒
if(x[i]>x[i-1]+h[i-1]) f[i][2]=max(f[i][2],f[i-1][2]+1);
if(x[i]>x[i-1])
{
f[i][2]=max(f[i][2],f[i-1][1]);
f[i][2]=max(f[i][2],f[i-1][0]+1);
}
}
printf("%d\n",max(max(f[n][0],f[n][1]),f[n][2]));
return 0;
}
http://codeforces.com/contest/545/problem/D
给你 n 个人,每个人要去银行窗口花 ti 的时间办事,每个人的等待时间是其在队列里前面的人的 ti 之和。一个人如果其 ti 大于等于其等待时间的话,他就高兴,否则不高兴。问排列整个队列后,最多能让多少个人高兴。
非常水的DP,显然要让 ti 尽量小的人尽量放在队列的前面。因此我们可以首先对 ti 进行排序,然后维护当前的等待时间( ti 前缀和),依次将 ti 从小到大放入队列里,并更新高兴的人的个数。但是需要注意,如果当前的 ti 比当前的等待时间小的话,那么现在无论如何都无法满足这个人的需求了,就需要把这个人放到队列的最末端,这样的话,就不会耽误他后面的人的等待时间了,还可以多满足一些后面的人。刚开始我就因为这个问题wa了一发。
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <queue>
#define MAXN 110000
using namespace std;
typedef long long int LL;
//priority_queue<LL>heap;
int n;
LL t[MAXN];
int main()
{
int ans=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%I64d",&t[i]);
sort(t+1,t+n+1);
//reverse(t+1,t+n+1);
LL nowt=0;
for(int i=1;i<=n;i++)
{
if(t[i]<nowt) continue;
ans++;
nowt+=t[i];
}
printf("%d\n",ans);
return 0;
}
http://codeforces.com/contest/545/problem/E
给你一个无向图,要你找出一个生成树,使得生成树里 S 到其他任何点的最短路和原图里 S 到其他任何点的最短路长度一样。找出满足这样的条件的最小的生成树。
首先,kruscal的做法显然是错误的,具体可以看第二个样例。
我们不妨用单源最短路算法先求出一个从 S 出发的最短路树,显然这样的树是满足要求的。但是还不能满足这个生成树最小的要求。
不妨改进堆优化Dijsktra。堆中不仅记录点和点到S的距离,还要加上一个标记:这个点是从哪条边走过来的。这样的话,假如在做dijsktra时,我们同时看到有两个点到 S 的最短路相同,我们就可以优先把前驱边权较小的那个点加入最短路树。
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <queue>
#define MAXN 610000
using namespace std;
typedef long long int LL;
struct edge
{
int u,v,id,next;
LL w;
}edges[MAXN];
int n,m;
int head[MAXN],nCount=1;
void AddEdge(int U,int V,LL W,int ID)
{
edges[++nCount].u=U;
edges[nCount].v=V;
edges[nCount].w=W;
edges[nCount].id=ID;
edges[nCount].next=head[U];
head[U]=nCount;
}
LL dist[MAXN];
bool vis[MAXN];
bool used[MAXN];
int pre[MAXN];
struct Info
{
int u;
LL w;
LL dis;
Info(int _u,LL _d,LL _w):u(_u),dis(_d),w(_w){}
};
bool operator<(Info a,Info b)
{
if(a.dis==b.dis) return a.w<b.w;
return a.dis<b.dis;
}
bool operator>(Info a,Info b)
{
if(a.dis==b.dis) return a.w>b.w;
return a.dis>b.dis;
}
priority_queue<Info,vector<Info>,greater<Info> >heap;
void heapdij(int S)
{
memset(dist,0x3f,sizeof(dist));
dist[S]=0;
heap.push(Info(S,0,0));
while(!heap.empty())
{
Info now=heap.top();
heap.pop();
int u=now.u;
if(vis[u]) continue;
vis[u]=true;
for(int p=head[u];p!=-1;p=edges[p].next)
{
int v=edges[p].v;
if(dist[u]+edges[p].w<=dist[v])
{
if(pre[v]!=-1) used[pre[v]]=false;
pre[v]=edges[p].id;
used[edges[p].id]=true;
dist[v]=dist[u]+edges[p].w;
heap.push(Info(v,dist[v],edges[p].w));
}
}
}
}
int main()
{
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int u,v;
LL w;
scanf("%d%d%I64d",&u,&v,&w);
AddEdge(u,v,w,i);
AddEdge(v,u,w,i);
}
int S;
scanf("%d",&S);
heapdij(S);
LL tot=0;
for(int i=1;i<=m;i++)
if(used[i]) tot+=(LL)edges[i*2].w;
printf("%I64d\n",tot);
for(int i=1;i<=m;i++)
if(used[i])
printf("%d ",i);
printf("\n");
return 0;
}