Codeforces Round #650 (Div. 3)

打的 vp,花了 1h 30min 切了前 6 个,后来花了 20min 把最后一题也切掉了.   

难度不大,但是想要进前 10 的话手速还是要快一点.   

A - Short Substrings

观察一下字符串,然后发现相同的保留一个就行. 

#include <bits/stdc++.h>   
#define N 1087   
#define ll long long 
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std; 
char str[N];  
void solve() {  
    scanf("%s",str+1); 
    int n=strlen(str+1); 
    printf("%c",str[1]);    
    for(int i=2;i<=n-2;i+=2) {  
        printf("%c",str[i]); 
    }
    printf("%c\n",str[n]);  
}
int main() { 
    // setIO("input");  
    int T; 
    scanf("%d",&T);   
    while(T--) solve();  
    return 0; 
}

  

B - Even Array

判断合不合法很简单,然后最小步数显然就是偶数/奇数不合法的位置个数.    

#include <bits/stdc++.h>    
#define N 1008  
#define ll long long 
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std;  
int a[N],c0,c1,c2; 
void solve() { 
    int n; 
    scanf("%d",&n); 
    c0=c1=c2=0; 
    for(int i=0;i<n;++i) {
        scanf("%d",&a[i]); 
        if(a[i]&1) ++c1; 
        else ++c0;  
        if((a[i]&1)!=(i&1)) {
            ++c2;    
        }
    }   
    if(c0!=(n+1)/2) printf("-1\n"); 
    else printf("%d\n",c2/2);  
}
int main() {
    // setIO("input");   
    int T; 
    scanf("%d",&T); 
    while(T--) solve(); 
    return 0; 
}

  

C - Social Distance

可以用差分数组维护 0 的连通块.   

连通块内贪心去填 1 就行,也就是 $\frac{len}{(k+1)}+(len \% (k+1) != 0)$  

#include <bits/stdc++.h>     
#define N 200009  
#define ll long long 
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std;   
char str[N];     
int a[N];  
void solve() {  
    int n,k; 
    scanf("%d%d",&n,&k);  
    scanf("%s",str+1);    
    for(int i=1;i<=n+3;++i) a[i]=0; 
    for(int i=1;i<=n;++i) {  
        if(str[i]=='1') {    
            a[max(1,i-k)]++;    
            a[min(i+k,n)+1]--;                  
        }
    }   
    int pre0=0,mx=0; 
    for(int i=1;i<=n;++i) 
    {
        a[i]+=a[i-1];  
        if(!a[i]) ++pre0;    
        else {  
            mx+=pre0/(k+1);   
            if(pre0%(k+1)) ++mx; 
            pre0=0; 
        }
    }  
    mx+=pre0/(k+1);
    if(pre0%(k+1)) ++mx;     
    printf("%d\n",mx);  
}
int main() {  
    // setIO("input");   
    int T; 
    scanf("%d",&T); 
    while(T--) solve(); 
    return 0; 
}

  

D - Task On The Board

从大到小依次考虑,显然最大的 b[i]=0,然后次大的 b[i]=该位置到所有最大的距离.  

这样可以判断序列中元素的 rank,然后再贪心去填字母就行了.

#include <bits/stdc++.h>    
#define N 53   
#define ll long long 
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std;      
char str[N]; 
int n,m,a[N],RK[N],cnt[N],num[N],ou[N];      
void solve() {   
    memset(RK,0,sizeof(RK));  
    memset(cnt,0,sizeof(cnt)); 
    memset(num,0,sizeof(num));  
    memset(ou,0,sizeof(ou));   
    scanf("%s",str+1);  
    n=strlen(str+1);        
    for(int i=1;i<=n;++i) ++num[str[i]-'a'];   
    scanf("%d",&m); 
    for(int i=1;i<=m;++i) scanf("%d",&a[i]);     
    int bu=0; 
    for(int i=1;;++i) {  
        int flag=0;    
        for(int j=1;j<=m;++j) {         
            if(RK[j]) continue;   
            int cur=0; 
            for(int t=1;t<=m;++t) {  
                if(RK[t]&&RK[t]<i) 
                    cur+=abs(t-j);  
            }  
            if(cur==a[j]) RK[j]=i,flag=1,++cnt[i];       
        }
        if(!flag) break;     
        bu=i;   
    }       
    int c=1;  
    for(int i=27;i>=0;--i) {  
        if(num[i]>=cnt[c]) {  
            ou[c]=i;   
            ++c;     
        }
        if(c>bu) break;  
    }
    for(int i=1;i<=m;++i) {  
        printf("%c",'a'+ou[RK[i]]);  
    }
    printf("\n");  
}
int main() {  
    // setIO("input");   
    int T; 
    scanf("%d",&T); 
    while(T--) solve();  
    return 0; 
}

  

E - Necklace Assembly

循环节为 $k$,意味着序列可以分成若干段,每段长度都为 k,且所有段相等.     

由于每段长度固定,所以可以二分段数.   

然后由于这里的循环节可能非常大,所以不妨分解 k 的因数,然后对每个因数求一下答案,最后取 max.   

#include <bits/stdc++.h>    
#define N 2008  
#define ll long long 
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std;   
int cnt[30],n,K; 
char S[N];   
int check(int x,int cur) {   
    int tmp=0; 
    for(int i=0;i<27;++i) {  
        tmp+=cnt[i]/x;  
    }
    return tmp>=cur;     
}
int cal(int p) { 
    int l=1,r=n,ans=0; 
    while(l<=r) { 
        int mid=(l+r)>>1;   
        if(check(mid,p)) ans=mid,l=mid+1; 
        else r=mid-1; 
    }  
    return ans*p;   
}
void solve() {   
    memset(cnt,0,sizeof(cnt));  
    scanf("%d%d",&n,&K);          
    scanf("%s",S+1); 
    for(int i=1;i<=n;++i) ++cnt[S[i]-'a'];   
    int ans=0;  
    for(int i=1;i<=n;++i) { 
        if(K%i==0) {
            ans=max(ans,cal(i));       
        }
    }  
    printf("%d\n",ans);  
}
int main() { 
    // setIO("input");  
    int T; 
    scanf("%d",&T); 
    while(T--) solve();  
    return 0; 
}

  

F2 - Flying Sort (Hard Version)

不难发现留下的是值域连续的一段,然后将值域两端分别扔到前后.   

那么问题就转化成求极长值域连续的段数长度.   

所有数互不相同显然很好求.  

对于出现数字相同的情况,不难发现构成一定是 零散 + 所有值严格取到 + 零散的形式.  

即只有最小和最大值可以不都取完,中间的必须都取完.   

这个直接用 DP 求就行. 

要特判中间没有严格取到的情况.  

#include <bits/stdc++.h>    
#define N 1000009  
#define ll long long 
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std;   
int f[N],a[N],A[N],fst[N],lst[N],pos[N],num[N],Num[N];    
void solve() {          
    int n;   
    scanf("%d",&n); 
    for(int i=1;i<=n;++i) {
        scanf("%d",&a[i]); 
        A[i]=a[i]; 
    }          
    sort(A+1,A+1+n);      
    int m=unique(A+1,A+1+n)-A-1;                         
    for(int i=1;i<=n+233;++i) f[i]=pos[i]=fst[i]=lst[i]=num[i]=Num[i]=0;   
    for(int i=1;i<=n;++i) a[i]=lower_bound(A+1,A+1+m,a[i])-A,++Num[a[i]];         
    for(int i=1;i<=n;++i) {   
        if(!fst[a[i]]) 
            fst[a[i]]=i;     
        lst[a[i]]=i;  
    }     
    int mx=0; 
    for(int i=1;i<=n;++i) {    
        f[i]=1;  
        if(fst[a[i]]==i) {  
            if(lst[a[i]-1]<i) f[i]=max(f[i],f[lst[a[i]-1]]+1);       
            f[i]=max(f[i],num[a[i]-1]+1);    
        }
        else f[i]=max(f[i],f[pos[a[i]]]+1);    
        ++num[a[i]];  
        pos[a[i]]=i;                   
        if(lst[a[i]]==i) mx=max(mx,f[i]+Num[a[i]+1]-num[a[i]+1]);       
        mx=max(mx,num[a[i]]+Num[a[i]+1]-num[a[i]+1]);   
    }         
    printf("%d\n",n-mx);  
}    
int main() { 
    // setIO("input");  
    int T;  
    scanf("%d",&T); 
    while(T--) solve();  
    return 0; 
}

  

posted @ 2020-06-28 19:25  EM-LGH  阅读(186)  评论(0编辑  收藏  举报