好久没打cf了,回来打一场,pp了4个题的fst了三个,掉了100多分。
好像cf已经三连掉从接近2000掉到1700+了。
老年选手打什么cf嘛。
题目链接:http://codeforces.com/contest/967
A. Mind the Gap (cf 967A)
傻逼题。
因为s等于60然后还要多加1,然后只进了一次位,然后就fst了。
#include
#define N 105
using namespace std;
int n,s,ans1,ans2,A[N],B[N];
int main()
{
scanf("%d%d",&n,&s);
for(int i=1;i<=n;i++)scanf("%d%d",&A[i],&B[i]);
if(A[1]*60+B[1]>=s+1){printf("0 0\n");return 0;}
A[n+1]=A[n]+10;B[n+1]=1;
for(int i=1;i<=n;i++)
{
int ti=(A[i+1]-A[i])*60+B[i+1]-B[i];
if(ti>=s*2+2)
{
ans1=A[i];ans2=B[i]+s+1;
while(ans2>=60)ans2-=60,ans1++;//!!!
break;
}
}
printf("%d %d\n",ans1,ans2);
return 0;
}
B. Watering System (cf 967B)
傻逼题,唯一过的题。
#include
#define N 100005
using namespace std;
int n,A,B,sum,s[N];
int main()
{
scanf("%d%d%d",&n,&A,&B);
for(int i=0;i"%d",&s[i]),sum+=s[i];
sort(s+1,s+n);
for(int i=0,j=n-1;iif(s[0]*A/sum>=B){printf("%d\n",i);return 0;}
sum-=s[j];
}
return 0;
}
C. Stairs and Elevators (cf 925A)
傻逼题。就近找楼梯或电梯就好了。
起点和终点都在同一层的时候如果两个点之间没有电梯和楼梯那我的写法就凉凉。
然后就fst了,加个特判就过了。
#include
#define inf 2100000000
#define N 100005
using namespace std;
int n,m,Q,c1,c2,v,ans,s1[N],s2[N];
int main()
{
int X1,Y1,X2,Y2,p1,p2;
scanf("%d%d%d%d%d",&n,&m,&c1,&c2,&v);
for(int i=1;i<=c1;i++)scanf("%d",&s1[i]);
for(int i=1;i<=c2;i++)scanf("%d",&s2[i]);
s1[++c1]=m+1;s2[++c2]=m+1;
scanf("%d",&Q);
while(Q--)
{
scanf("%d%d%d%d",&X1,&Y1,&X2,&Y2);ans=inf;
if(X1==X2){printf("%d\n",abs(Y1-Y2));continue;}
if(Y1>Y2)swap(X1,X2),swap(Y1,Y2);
int tmp=abs(X1-X2)/v;
if(abs(X1-X2)%v)tmp++;
p1=lower_bound(s1+1,s1+c1+1,Y1)-s1;
while(s1[p1]if(s1[p1]<=m)ans=min(ans,abs(s1[p1]-Y1)+abs(s1[p1]-Y2)+abs(X1-X2));
p1--;
if(s1[p1])ans=min(ans,abs(s1[p1]-Y1)+abs(s1[p1]-Y2)+abs(X1-X2));
p2=lower_bound(s2+1,s2+c2+1,Y1)-s2;
while(s2[p2]if(s2[p2]<=m)ans=min(ans,abs(s2[p2]-Y1)+abs(s2[p2]-Y2)+tmp);
p2--;
if(s2[p2])ans=min(ans,abs(s2[p2]-Y1)+abs(s2[p2]-Y2)+tmp);
printf("%d\n",ans);
}
return 0;
}
D. Resource Distribution (cf 925B)
枚举其中一个服务器的答案,贪心找出最优解,判断剩下的空间能否满足第二个服务器。
对于判断过程,等价于求区间最大值。猜了个不知道对不对的单峰结论然后直接上三分了。
因为一些边界问题wa了最后一个点。
#include
#define ll long long
#define N 300005
using namespace std;
int n,po[N],tot;ll x1,x2;
struct info{
int x,id;
bool operator<(const info &p)const{return xx;}
}s[N];
ll cal(int x,int len)
{
return (ll)(n-x+1-len)*s[x].x;
}
int qry(int l,int r,int tmp)
{
if(l>r)return 0;
while(r-l>1)
{
int len=(r-l+1)/3;
int lx=l+len,rx=r-len;
if(cal(lx,tmp)else r=rx;
}
if(cal(l,tmp)>cal(r,tmp))return l;
return r;
}
int main()
{
int x,num,pos,p1,p2,p;ll v1,v2;
scanf("%d%lld%lld",&n,&x1,&x2);
for(int i=1;i<=n;i++)
scanf("%d",&x),s[i]=(info){x,i};
sort(s+1,s+n+1);
for(int i=1;i<=n;i++)
{
num=x1/i;if(x1%i)num++;
pos=lower_bound(s+1,s+n+1,(info){num,0})-s;
while(pos<=n&&s[pos].xpos++;
if(pos+i-1>n)continue;
p1=qry(1,pos-1,i);p2=qry(pos+i,n,0);
v1=p1?(n-p1-i+1)*s[p1].x:0;
v2=p2?v2=(n-p2+1)*s[p2].x:0;
if(max(v1,v2)continue;
tot=0;p=v1>v2?p1:p2;
for(int j=n;j>=pos+i&&j>=p;j--)po[++tot]=j;
for(int j=pos-1;j>=p;j--)po[++tot]=j;
printf("Yes\n");
printf("%d %d\n",i,tot);
for(int j=pos;j<pos+i;j++)printf("%d ",s[j].id);
printf("\n");
for(int j=1;j<=tot;j++)printf("%d ",s[po[j]].id);
printf("\n");
return 0;
}
printf("No\n");
return 0;
}
E. Big Secret (cf 925C)
其实这题挺傻逼的没想出来真不应该。
我们考虑异或前缀和,将这个数字异或某个数等于选择若干个为0的位置然后把这些位置变为1。
对答案有影响的只能是最高位。
所以每次贪心选择尽量小的位置,异或一个最高位是这个位置的数字,依次更新就是答案。
#include
#define ll long long
#define N 100005
#define M 62
using namespace std;
int n,pos[M];ll ans[N],now;
vector t[M];
int main()
{
ll x;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%I64d",&x);
for(int j=60;j>=0;j--)
if(x>>j&1){t[j].push_back(x);break;}
}
for(int i=1;i<=n;i++)
{
int flag=0;
for(int j=0;j<=60;j++)
if(!((now>>j)&1))
{
if(pos[j]==t[j].size())continue;
ans[i]=t[j][pos[j]];flag=1;
now^=t[j][pos[j]];pos[j]++;break;
}
if(!flag){printf("No\n");return 0;}
}
printf("Yes\n");
for(int i=1;i<=n;i++)printf("%I64d ",ans[i]);
printf("\n");
return 0;
}
F. Aztec Catacombs (cf 925D)
没想到这是一个纯构造题。
一条合法的路径要么所有的边初始都能走,要么就是路径上的某一个点经过两次,第二次的时候直接到终点。
我们考虑最短的重复经过一个点的路径,这条路径长度最少为4。
所以如果原图上1到n的最短路径长度小于4等于4那么直接取就好了。
不然的话,如贵存在一个点,它到1号点的最短路径长度为2,我们从1跑到它再回1然后去n,这样答案是4。
如果不存在这样的点的话,那我们就把所有与1相连的点拿出来分成若干个联通快。
我们需要寻找一条路径,它从1到某个点,跑一个三元环回到那个点,然后到n。
如果一个点的度小于那个联通块大小-1,那么以它为起点找到一个到它距离为2的点然后构造就好了。
不然的话就无解。
#include
#define N 300005
using namespace std;
int n,m,w[N],d[N],blo[N],size[N],cur,pre[N];
int k,la[N],ff[N*2],flag[N],q[N],tot,po[N];
struct node{int a,b;}e[N*2];
void add(int a,int b)
{
e[++k]=(node){a,b};ff[k]=la[a];la[a]=k;
e[++k]=(node){b,a};ff[k]=la[b];la[b]=k;
}
void bfs()
{
int l=1,r=2;q[1]=1;
while(lint x=q[l++];
for(int a=la[x];a;a=ff[a])
if(!w[e[a].b]&&e[a].b>1)
q[r]=e[a].b,pre[q[r]]=x,w[q[r]]=w[x]+1,r++;
}
}
void dfs(int x)
{
size[blo[x]=cur]++;flag[x]=1;
for(int a=la[x];a;a=ff[a])
if(e[a].b!=1)
{
d[x]++;
if(!flag[e[a].b])dfs(e[a].b);
}
}
int bfs(int S)
{
int l=1,r=2;q[1]=S;
while(lint x=q[l++];
if(w[x]==2)return x;
for(int a=la[x];a;a=ff[a])
if(!w[e[a].b]&&e[a].b!=S&&e[a].b!=1)
q[r]=e[a].b,pre[q[r]]=x,w[q[r]]=w[x]+1,r++;
}
}
int main()
{
int a,b;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d%d",&a,&b),add(a,b);
bfs();
if(w[n]&&w[n]<=4)
{
for(int x=n;x;x=pre[x])po[++tot]=x;
printf("%d\n",tot-1);
while(tot)printf("%d ",po[tot--]);
printf("\n");return 0;
}
for(int i=1;i<=n;i++)
{
if(w[i]==2)
{
printf("4\n");
printf("1 %d %d 1 %d\n",pre[i],i,n);
return 0;
}
}
memset(w,0,sizeof(w));
memset(pre,0,sizeof(pre));
for(int a=la[1];a;a=ff[a])
if(!flag[e[a].b])++cur,dfs(e[a].b);
for(int a=la[1];a;a=ff[a])
if(d[e[a].b]1)
{
int pos=bfs(e[a].b);
for(int x=pos;x;x=pre[x])po[++tot]=x;
printf("5\n1 ");
while(tot)printf("%d ",po[tot--]);
printf("%d %d\n",e[a].b,n);
return 0;
}
printf("-1\n");
return 0;
}