Codeforces Round #471 (Div. 2)

比賽鏈接

QAQ終於補完了這場的題。。感覺後面幾題還都挺好的就寫個(非常)簡略的總結叭。

A. Feed the cat

簡單貪心+模擬。

#include<bits/stdc++.h>
#define rep(i,x,y) for (int i=(x); i<=(y); i++)
#define ll long long
using namespace std;
long double ans;
int main(){
    int a,b,H,D,C,N;
    scanf("%d%d",&a,&b);
    scanf("%d%d%d%d",&H,&D,&C,&N);
    ans=((H-1)/N+1)*C;// printf("%.15lf\n",(double)ans);
    if (a<20) H+=D*((19-a)*60+60-b);
    //printf("%d\n",H);
    ans=min(ans,(long double)((int)((H-1)/N+1)*C)*0.8);
    printf("%.15lf\n",(double)ans);
    return 0;
}

B. Not simply beatiful strings

枚舉幾種情況特判一下即可。

#include<bits/stdc++.h>
#define rep(i,x,y) for (int i=(x); i<=(y); i++)
#define ll long long
#define N 100005
using namespace std;
int n,ch[30]; char s[N];
int main(){
    scanf("%s",s+1); n=strlen(s+1);
    int cnt=0;
    rep (i,1,n){
        if (!ch[s[i]-'a']) cnt++;
        ch[s[i]-'a']++;
    }
    if (cnt<=1 || cnt>4){ puts("No"); exit(0); }
    int mx=0; rep (i,0,25) mx=max(mx,ch[i]);
    int mi=n+1; rep (i,0,25) if (ch[i]) mi=min(mi,ch[i]);
    if (cnt==3 && mx==1){ puts("No"); exit(0); }
    if (cnt==2 && mi==1){ puts("No"); exit(0); }
    puts("Yes");
    return 0;
}

C. Sad powers

先轉化爲求 [1,r][1,l1] ,然後按照 n13 分類一下。 106 以內的預處理出3次及以上的。2次的直接開根號下取整即可。

//考場上搞了很久爆了很多發qaq,以至於分數特別的低。。

#include<bits/stdc++.h>
#define rep(i,x,y) for (int i=(x); i<=(y); i++)
#define ll long long
#define N 1000005
#define inf 1000000000000000000ll
#define sqr(x) ((x)*(x))
using namespace std;
ll a[N*30],l,r,ans; int q,tot;
void pre(){
    rep (i,2,1000000){
        long double tmp=(long double)i*i*i;
        while (tmp && tmp<=(long double)inf){
            if ((ll)floor(sqrt(tmp))!=sqrt(tmp)) a[++tot]=(ll)tmp;
            if (tmp*(long double)i<=inf) tmp*=i; else break;
        }
    }
    sort(a+1,a+1+tot); tot=unique(a+1,a+1+tot)-a-1;
}
int main(){
    /*freopen("C.in","r",stdin);
    freopen("C.out","w",stdout);*/
    pre();// printf("%d\n",tot);
    scanf("%d",&q);
    while (q--){
        cin>>l>>r;
        int pl=upper_bound(a+1,a+1+tot,l-1)-a-1;
        int pr=upper_bound(a+1,a+1+tot,r)-a-1;
        ans=pr-pl;
        ans+=(ll)sqrt(r);
        ans-=(ll)sqrt(l-1);
        cout<<ans<<endl;
    }
    return 0;
}

D. Scissors

思路比較顯然,就是枚舉串 t 的斷點然後判斷是否可行。kmp預處理出串 t 和串 s 拼接起來的 next 數組以及翻轉後的,然後預處理出 w1 w2w1[i] 表示串 t+snext 值爲 i 的最小在原串中的下標, w2[i] 表示 t+s 翻轉後的串中 next 值爲 i 的最大在原串中的下標。然後就可以 O(1) 判斷了。

#include<bits/stdc++.h>
#define rep(i,x,y) for (int i=(x); i<=(y); i++)
#define per(i,x,y) for (int i=(x); i>=(y); i--)
#define ll long long
#define N 1000005
#define all(x) (x).begin(),(x).end()
using namespace std;
int n,m,k,len,f[N],g[N],w1[N],w2[N]; char s[N],t[N],str[N];
void get_next(char s[],int nxt[]){
    int k=0; nxt[1]=0;
    rep (i,2,len){
        while (k && s[k+1]!=s[i]) k=nxt[k];
        if (s[k+1]==s[i]) nxt[i]=++k; else nxt[i]=k;
    }
}
int main(){
    scanf("%d%d%d%s%s",&n,&m,&k,s+1,t+1);
    if (k*2>n || k*2<m){ puts("No"); exit(0); }
    len=0;
    rep (i,1,m) str[++len]=t[i]; str[++len]='#';
    rep (i,1,n) str[++len]=s[i];
    get_next(str,f);
    len=0;
    rep (i,1,n) str[++len]=s[i]; str[++len]='#';
    rep (i,1,m) str[++len]=t[i]; reverse(str+1,str+1+len);
    get_next(str,g);
    rep (i,m+2,n+m+1) if (f[i]>=m){
        int p1=i-m-1; p1=max(p1-2*k,0);
        printf("Yes\n%d %d\n",p1+1,p1+1+k); exit(0);
    }
    rep (i,0,n) w1[i]=n+1;
    rep (i,m+2,n+m+1){
        if (i-m-1>=k){
            int tmp=f[i];
            while(tmp){
                if (i-m-1<w1[tmp]) w1[tmp]=i-m-1; else break;
                tmp=f[tmp];
            }
            tmp=g[i];
            while (tmp){
                if (n-(i-m-1)+1>w2[tmp]) w2[tmp]=n-(i-m-1)+1; else break;
                tmp=g[tmp];
            }
        }
    }
    w1[0]=0; w2[0]=n+1;
    rep (i,1,min(k,m)){//左邊取i個
        if (m-i>k) continue;
        int p1=w1[i]-k+1,p2=w2[m-i];
        if (p1>=1 && p2+k-1<=n && w1[i]<p2){
            printf("Yes\n%d %d\n",p1,p2); exit(0);
        }
    }
    puts("No");
    return 0;
}

E. Icicles

見註釋。

/*
*   枚舉T:
*   tim_i表示在T點發射聲波,i號點降落的時間
*   i<T:tim_i=a[i]+T-i; i>=T:tim_i=a[i]+i-T;
*   找到最小的滿足tim_j<j的j
*   ans=max(min(tim_i|1<=i<j),min(tim_i|j<=i<=n));
*/
#include<bits/stdc++.h>
#define rep(i,x,y) for (int i=(x); i<=(y); i++)
#define ll long long
#define N 100005
#define inf 1000000000
using namespace std;
ll read(){
    char ch=getchar(); ll x=0; int op=1;
    for (; !isdigit(ch); ch=getchar()) if (ch=='-') op=-1;
    for (; isdigit(ch); ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
    return x*op;
}
int n,L,ans,a[N],pre[N][25],suf[N][25],mi[N][25],lg[N];
int get_min(int x,int y){
    if (x>y) return inf;
    int tmp=lg[y-x+1]; return min(mi[x][tmp],mi[y-(1<<tmp)+1][tmp]);
}
int get_min1(int x,int y){
    if (x>y) return inf;
    int tmp=lg[y-x+1]; return min(pre[x][tmp],pre[y-(1<<tmp)+1][tmp]);
}
int get_min2(int x,int y){
    if (x>y) return inf;
    int tmp=lg[y-x+1]; return min(suf[x][tmp],suf[y-(1<<tmp)+1][tmp]);
}
int main(){
    n=read(); rep (i,1,n) mi[i][0]=a[i]=read();
    rep (i,1,n) pre[i][0]=a[i]-i;
    rep (i,1,n) suf[i][0]=a[i]+i;
    rep (j,1,20) for (int i=1; i+(1<<j-1)<=n; i++){
        mi[i][j]=min(mi[i][j-1],mi[i+(1<<j-1)][j-1]);
        pre[i][j]=min(pre[i][j-1],pre[i+(1<<j-1)][j-1]);
        suf[i][j]=min(suf[i][j-1],suf[i+(1<<j-1)][j-1]);
    }
    lg[1]=0; rep (i,2,n) lg[i]=lg[i>>1]+1;
    L=1; ans=inf;
    rep (T,1,n){
        while (L<=T && T>=2*L-a[L]) L++;
        //j<T: a[j]+T-j<j ---> T<2*j-a[j]
        int j=-1;
        if (L<=T) j=L;
        else {
            int l=T,r=n,mid,pos=-1;
            while (l<=r){
                mid=l+r>>1;
                if (get_min(T,mid)<T) pos=mid,r=mid-1; else l=mid+1;
            }
            if (pos==-1) continue; j=pos;
        }
        //j>T: a[j]+j-T<j ---> T>a[j]
        int x,y;
        if (j<=T){
            x=get_min1(1,j-1)+T;
            y=min(get_min1(j,T)+T,get_min2(T+1,n)-T);
        } else{
            x=min(get_min1(1,T)+T,get_min2(T+1,j-1)-T);
            y=get_min2(j,n)-T;
        }
        ans=min(ans,max(x,y));
    }
    if (ans==inf) cout<<-1<<endl; else cout<<ans<<endl;
    return 0;
}

F. Heaps

樹形dp。見註釋。

#include<bits/stdc++.h>
#define rep(i,x,y) for (int i=(x); i<=(y); i++)
#define per(i,x,y) for (int i=(x); i>=(y); i--)
#define ll long long
#define N 300005
using namespace std;
ll read(){
    char ch=getchar(); ll x=0; int op=1;
    for (; !isdigit(ch); ch=getchar()) if (ch=='-') op=-1;
    for (; isdigit(ch); ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
    return x*op;
}
int n,cnt,head[N],mx[N],dp[N][25],q[N]; ll ans;
struct edge{
    int to,nxt;
}e[N<<1];
void adde(int x,int y){
    e[++cnt].to=y; e[cnt].nxt=head[x]; head[x]=cnt;
}
void ins(int x,int y){
    adde(x,y); adde(y,x);
}
const bool cmp(const int x,const int y){ return x>y; }
void dfs(int u,int pr){
    for (int i=head[u],v; i; i=e[i].nxt) if ((v=e[i].to)!=pr){
        dfs(v,u); mx[u]=max(mx[u],mx[v]);
    }
    ans+=++mx[u];//k=1的情況
    dp[u][1]=n;//dp[i][j]表示i號點,深度爲j的最大能取到的k
    rep (i,2,20){//深度最多不超過log_{k}^{n},因爲最多在滿多叉樹的時候滿足要求,此時深度爲logn
        int tp=0;
        for (int j=head[u],v; j; j=e[j].nxt) if ((v=e[j].to)!=pr) q[++tp]=dp[v][i-1];
        sort(q+1,q+1+tp,cmp);
        per (j,tp,2) if (q[j]>=j){ dp[u][i]=j; break; }//第k大的值>=k說明能取到k
    }
}
void solve(int u,int pr){
    for (int i=head[u],v; i; i=e[i].nxt) if ((v=e[i].to)!=pr){
        solve(v,u);
        rep (j,1,20) dp[u][j]=max(dp[u][j],dp[v][j]);
    }
    rep (i,1,20){
        ans+=(ll)(dp[u][i]-dp[u][i+1])*i;
        if (dp[u][i+1]==0){ ans-=i; break; }
    }
}
int main(){
    n=read();
    rep (i,1,n-1){
        int x=read(),y=read(); ins(x,y);
    }
    dfs(1,0); solve(1,0); cout<<ans<<endl;
    return 0;
}

總結

賽時通過ABC,rk53,rating+91.

成功地將我掉藍的大號升回了紫qnq。

//然鵝自己還是菜的一匹啊

//現在似乎一打d1就掉分啊qaq我該怎麼辦

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章