Contest:http://codeforces.com/contest/1204
A. BowWow and the Timetable(规律)
题目链接:http://codeforces.com/contest/1204/problem/A
题目大意:火车的开出时间是4^k。给出出发时间(二进制数),判断错过了多少趟火车。
思路:很容易发现,由于是一个合法的二进制数,因此第一位必定为1,那么我们判断有多少位就好了。两位一个4,相当于len/2个列车,如果是奇数&&后面有1的话,说明仍然错过了最近的一站。
ACCode:
int main(){
string s;
while(cin>>s){
int len=s.size();
int ans=0,flag=0;
if(len&1){//len奇数
ans=len/2;
for(int i=len-1;i>0;--i){
if(s[i]=='1') flag=1;
}
if(flag) ++ans;
}
else{
ans=len/2;
}cout<<ans<<endl;
}
}
B. Mislove Has Lost an Array(简单模拟)
题目链接:http://codeforces.com/contest/1204/problem/B
题目大意:给出数组长度,种类数的下界和上界。求数组元素的最大和,和最小和。数组中元素只能是2^k,且必须存在2^(k-1)。
思路:最小值,满足下届的前面全是1.最大值,满足上界的后面全是最大值。
ACCode:
int n,l,r;
int main(){
while(~scanf("%d%d%d",&n,&l,&r)){
ll sum1=0,sum2=0,cnt=0;
for(int i=1;i<=l;++i){
sum1+=(1ll<<(i-1));
}sum1+=n-l;
// printf("sum1=%lld\n",sum1);
for(int i=1;i<=r;++i){
sum2+=(1ll<<(i-1));
// printf("sum=%lld\n",sum2);
}
for(int i=1;i<=n-r;++i){
sum2+=(1ll<<(r-1));
// printf("%lld\n",sum2);
}printf("%lld %lld\n",sum1,sum2);
}
}
C. Anna, Svyatoslav and Maps(Floyd判断最短路)
题目链接:http://codeforces.com/contest/1204/problem/C
题目大意:给出一个n个点的有向图。给你一条路径,输出缩小之后的路径。路径可以被缩小a->b->c,缩小a->c只能是b只连接a和c。
思路:跑一边Floyd,就可以得到所有联通的点和最短路了。对于每个点,如果之间的距离就是最短路,那么就可以直接相连,否者中间必定存在其他的最短路径。两个同样的元素不可相邻:比如a->b->a不可缩减成a->a。特判一下就好了。
ACCode:
char S[MAXN];
int MP[MAXN][MAXN],Cnt[MAXN][MAXN];
int A[MAXN*MAXN*MAXN];
int Ans[MAXN*MAXN*MAXN],tot;
int n;
void Floyd(){
for(int k=1;k<=n;++k){
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
if(MP[i][j]>MP[i][k]+MP[k][j]){
MP[i][j]=MP[i][k]+MP[k][j];
Cnt[i][j]=1;
}
else if(MP[i][j]==MP[i][k]+MP[k][j]){
Cnt[i][j]++;
}
}
}
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%s",&S);
// printf("S=%s\n",S);
for(int j=1;j<=n;++j){
if(S[j-1]=='1') MP[i][j]=1;
else MP[i][j]=INF32;
}
}Floyd();
// for(int i=1;i<=n;++i){
// for(int j=1;j<=n;++j){
// printf("%d ",MP[i][j]);
// }printf("\n");
// }
// for(int i=1;i<=n;++i){
// for(int j=1;j<=n;++j){
// printf("%d ",Cnt[i][j]);
// }printf("\n");
// }
int m;scanf("%d",&m);
for(int i=1;i<=m;++i){
scanf("%d",&A[i]);
}
tot=0;
for(int i=1,j;i<=m;i=j){
j=i+2;
// printf("judge: i=%d j=%d MP[%d][%d]=%d\n",i,j,A[i],A[j],MP[A[i]][A[j]]);
while(j<=m&&j-i<=MP[A[i]][A[j]]) ++j;--j;//[i,j]中都可以省略[i,j+1]不可省略
if(A[i]==A[j]) --j;
Ans[++tot]=A[i];
//if(j==m&&i<m) Ans[++tot]=A[j];//一直到最后
// printf("end: i=%d j=%d\n",i,j);
}
printf("%d\n%d",tot,Ans[1]);
for(int i=2;i<=tot;++i) printf(" %d",Ans[i]);printf("\n");
}
D2. Kirk and a Binary String (hard version)(规律+线段树)
题目链接:http://codeforces.com/contest/1204/problem/D2
题目大意:给出一个01串S,让你求出另一个串P满足长度相等。所有区间的不减子序列长度相等(注意是子序列,不是子串).
思路:经过观察我们发现,可将01串的[1,x]的最长不减子序列长度求出:
然后发现,每个0的最多上升空间,然后我们就可以判断能否将1修改为0,很明显,将1修改为0后,影响的是后面的0.所以用线段树维护一下最多的修改次数就好了。
ACCode:
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#include<time.h>
#include<math.h>
// srand((unsigned)time(NULL));rand();
#include<map>
#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
#define ll long long
#define PII pair<int,int>
#define PLL pair<ll,ll>
#define clean(a,b) memset(a,b,sizeof(a))
using namespace std;
const int MAXN=1e5+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll MOD=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;
//unsigned register
// ios::sync_with_stdio(false)
// freopen(".in","r",stdin);freopen(".out","w",stdout);
struct SegTree{
struct Node{
int l,r;
int mxadd;
//可达到的最大值 当前值 可增加多少
int lazy;
};
Node Tree[MAXN<<2];
void PushUp(int rt){
Tree[rt].mxadd=min(Tree[rt<<1].mxadd,Tree[rt<<1|1].mxadd);
}
void PushDown(int rt){
if(Tree[rt].lazy){
Tree[rt<<1].lazy=Tree[rt<<1|1].lazy=Tree[rt].lazy;
Tree[rt<<1].mxadd+=Tree[rt].lazy;
Tree[rt<<1|1].mxadd+=Tree[rt].lazy;
Tree[rt].lazy=0;
}
}
void Build(int l,int r,int rt,int A[]){
if(l>r) return ;
Tree[rt].l=l;Tree[rt].r=r;
Tree[rt].lazy=0;
if(l==r){
Tree[rt].mxadd=A[l];
return ;
}int mid=(l+r)>>1;
Build(l,mid,rt<<1,A);Build(mid+1,r,rt<<1|1,A);
PushUp(rt);
}
void Update(int ql,int qr,int val,int rt){//区间修改+1
if(ql>qr) return ;
if(ql<=Tree[rt].l&&Tree[rt].r<=qr){
Tree[rt].mxadd+=val;
Tree[rt].lazy+=val;
return ;
}PushDown(rt);
if(qr<=Tree[rt<<1].r) Update(ql,qr,val,rt<<1);
else if(ql>=Tree[rt<<1|1].l) Update(ql,qr,val,rt<<1|1);
else{
Update(ql,qr,val,rt<<1);
Update(ql,qr,val,rt<<1|1);
}PushUp(rt);
}
void Show(int rt){
printf("l=%d r=%d mxadd=%d lazy=%d\n",Tree[rt].l,Tree[rt].r,Tree[rt].mxadd,Tree[rt].lazy);
if(Tree[rt].l==Tree[rt].r) return ;
Show(rt<<1);Show(rt<<1|1);
}
};
SegTree Seg;
char S[MAXN];
int A[MAXN],B[MAXN],C[MAXN],Ans[MAXN];
int main(){
// freopen("D.in","r",stdin);freopen("D.out","w",stdout);
while(~scanf("%s",&S)){
int len=strlen(S);
int o=0,z=0;
for(int i=0,mx=0;i<len;++i){
if(S[i]=='1'){ ++o; A[i]=++mx; }
else{ A[i]=++z; mx=max(mx,A[i]); }
}
// for(int i=0;i<len;++i) printf("%c ",S[i]);printf("\n");
// for(int i=0;i<len;++i) printf("%d ",A[i]);printf("\n");
for(int i=1;i<=len;++i) B[i]=max(B[i-1],A[i-1]);
// for(int i=1;i<=len;++i) printf("%d ",B[i]);printf("\n");
for(int i=1,j=0;i<=len;++i){//最大可上升多少
if(S[i-1]=='0'){
C[++j]=B[i]-A[i-1];
}
}
// for(int i=1;i<=z;++i) printf("%d ",C[i]);printf("\n");
Seg.Build(1,z,1,C);
// Seg.Show(1);printf("\n");
for(int i=1,j=1;i<=len;++i){
//后面修改的0为[j,z]
// printf("i=%d j=%d\n",i,j);
if(S[i-1]=='1'){//判断是否可以缩减为0
Seg.Update(j,z,-1,1);
Seg.Update(1,j-1,100,1);//排除前面的影响
if(Seg.Tree[1].mxadd<0){
Seg.Update(j,z,1,1);
Ans[i]=1;
// printf("NotChange\n");
}
else Ans[i]=0;
}
else{
Ans[i]=0;
++j;
}
// Seg.Show(1);printf("\n");
}
for(int i=1;i<=len;++i) printf("%d",Ans[i]);printf("\n");
}
}
//0111001100111011101000
//0011001100001000000000
//0011001100001011101000