UOJ Logo heqingyu的博客

博客

普及转提高模拟赛第8场(Day1)

2018-03-29 18:54:51 By heqingyu

这次博客写的好晚啊。。。。太忙了。。。太强了。。。

这次模拟赛打的有些不如意,本想着寒假做了挺多题,应该不错了,但是发现还是菜的一批

被C班霸霸们摁在鞋底摩擦啊。。。太强了。。。@丁思源

然后就是各种zz错误,可能是没有从OJ的从来不调代码这个习惯转成打OI赛制把。。。

T1:

最水的字符串判断题,但是最好不要用string,可能会爆。。。

然后zz的我把not成功的打成了no。。。。

code:

#include<bits/stdc++.h>
using namespace std;
int Q;
char s[10010];
int main(){
    freopen("acid.in","r",stdin);
    freopen("acid.out","w",stdout);
    scanf("%d",&Q);
    while(Q--){
        scanf("%s",s+1);
        int l=strlen(s+1);
        if(s[l-1]=='i'&&s[l]=='c'){
            if(s[1]=='h'&&s[2]=='y'&&s[3]=='d'&&s[4]=='r'&&s[5]=='o') puts("non-metal acid");
            else puts("polyatomic acid");
        }
        else puts("not an acid");
    }
    return 0;
}

T2:

这是一道贪心的题,考虑肯定每次关一扇门最劣,关两扇门最优

于是可以分别从左向右或者从右向左模拟关门,求出答案

code:

#include<bits/stdc++.h>
using namespace std;
int ans1,ans2,a[10010],n;
int main(){
    freopen("lock.in","r",stdin);
    freopen("lock.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),ans2+=a[i];
    for(int i=1;i<=n;i++){
        if(!a[i]) continue;
        ans1++;
        a[i]=0;
        a[i+1]=0;
    }
    printf("%d %d",ans1,ans2);
    return 0;
}

T3:

大模拟,暴力出奇迹。。。

code:

#include<bits/stdc++.h>
using namespace std;
int kx,ky,ans,T;
char mp[12][12];
int vis[12][12];
const int n=8,q=8,r=4,b=4,k=8;
const int qt[q][2]={1,1,1,0,1,-1,0,-1,-1,-1,-1,0,-1,1,0,1};
const int rt[r][2]={1,0,0,1,-1,0,0,-1};
const int bt[b][2]={1,1,1,-1,-1,-1,-1,1};
const int kt[k][2]={1,2,2,1,-1,2,2,-1,1,-2,-2,1,-1,-2,-2,-1};
bool check(int x,int y){return x>=1&&x<=n&&y>=1&&y<=n;}
bool solve(){
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;i++)for(int j=1;j<=n;j++){
        if(mp[i][j]=='k') kx=i,ky=j;
        else if(mp[i][j]=='Q'){
            for(int k=0;k<q;k++)
                for(int x=i+qt[k][0],y=j+qt[k][1];check(x,y)&&(mp[x][y]=='#'||mp[x][y]=='k');x+=qt[k][0],y+=qt[k][1])
                    vis[x][y]=1;
        }else if(mp[i][j]=='R'){
            for(int k=0;k<r;k++)
                for(int x=i+rt[k][0],y=j+rt[k][1];check(x,y)&&(mp[x][y]=='#'||mp[x][y]=='k');x+=rt[k][0],y+=rt[k][1])
                    vis[x][y]=1;
        }else if(mp[i][j]=='B'){
            for(int k=0;k<b;k++)
                for(int x=i+bt[k][0],y=j+bt[k][1];check(x,y)&&(mp[x][y]=='#'||mp[x][y]=='k');x+=bt[k][0],y+=bt[k][1])
                    vis[x][y]=1;
        }else if(mp[i][j]=='K'){
            for(int k=0;k<k;k++)
                if(check(i+kt[k][0],j+kt[k][1]))
                    vis[i+kt[k][0]][j+kt[k][1]]=1;
        }else if(i>1&&mp[i][j]=='P'){
            if(check(i-1,j-1))    vis[i-1][j-1]=1;
            if(check(i-1,j+1))    vis[i-1][j+1]=1;
        }
    }    return vis[kx][ky];
}
int main(){
    freopen("check.in","r",stdin);
    freopen("check.out","w",stdout);
    scanf("%d",&T);
    while(T--){
        ans=0;
        for(int i=0;i<=n+1;i++)
            mp[0][i]=mp[n+1][i]='#',
            mp[i][0]=mp[i][n+1]='#';
        for(int i=1;i<=8;i++)scanf("%s",mp[i]+1);
        ans=solve();
        for(int i=1;i<=8;i++){
            if(mp[1][i]=='#'&&mp[2][i]=='P'){
                mp[2][i]='#';mp[1][i]='P';
                mp[1][i]='Q',ans+=solve();
                mp[1][i]='R',ans+=solve();
                mp[1][i]='B',ans+=solve();
                mp[1][i]='K',ans+=solve(); 
                mp[1][i]='#',mp[2][i]='P';
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

T4:

考虑要让分解次数尽量多,肯定要分解成尽量大的质因子

所以可以暴力枚举出小的约数,然后除n就可以得出最大的质因子了。。。

不过貌似也可以从大向小枚举,没试过。。。

code:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n,x;
ll ans;
ll calc(ll k){
    ll cnt=k;
    while(k>1){
        ll tot=-1;
        for(int i=2;i<=sqrt(k);i++)if(k%i==0){tot=i;break;}
        if(tot==-1){cnt++;break;}
        cnt+=k/tot;
        k/=tot;
    }
    return cnt;
}
int main(){
    freopen("sticks.in","r",stdin);
    freopen("sticks.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%lld",&x),ans+=calc(x);
    printf("%lld",ans);
    return 0;
}

T5:

首先可以得出一个n^2的DP:

#include <bits/stdc++.h>
#define mxn 100000
using namespace std;
typedef long long ll;
bool o[mxn|1];
ll rs,n,h[mxn|1],p[mxn|1],f[mxn|1];
int main() {
    freopen("race.in","r",stdin);
    freopen("race.out","w",stdout);
    scanf("%lld",&n);
    for(int i=1;i<=n;i++)
        scanf("%lld",h+i);
    for(int i=2;i<=n;i++)
        scanf("%lld",p+i);
    memset(f,0x3f,sizeof(f));
    f[1]=0;
    for(int i=1;i<n;i++)
        for(int j=i+1;j<=n;j++)
            if(h[j]>h[i]) {
                f[j]=min(f[j],f[i]+h[j]-h[i]+p[j]);
                o[i]=1;    break;
            } else {
                f[j]=min(f[j],f[i]+h[i]-h[j]+p[j]);
            }
    rs=0x3f3f3f3f3f3f3f3f;
    for(int i=1;i<=n;i++)
        if(!o[i])    rs=min(rs,f[i]);
    printf("%lld\n",rs+n);
    return 0;
}

但是这样只有68分。。。

然后我们想到倒着转移,从n枚举到1

发现f[i]转移是从之前所有的f[j]中代价最小的那个转移过来的。。。

于是开一个单调栈来维护这一切。。。

code:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n,p[100010],f[100010];
ll st[100010][2],top;
ll h[100010];
int main(){
    freopen("race.in","r",stdin);
    freopen("race.out","w",stdout);
    scanf("%lld",&n);
    for(int i=1;i<=n;i++)scanf("%lld",&h[i]);
    for(int i=2;i<=n;i++)scanf("%lld",&p[i]);
    memset(f,127,sizeof(f));
    for(ll i=n;i>=1;i--){
        ll cnt=1e18;
        while(top&&h[st[top][0]]<=h[i]){
            cnt=min(st[top][1],cnt);
            f[i]=min(f[i],st[top][1]-i+h[i]);
            top--;
        }
        if(!top) f[i]=min(f[i],n-i+1);
        else f[i]=min(f[i],st[top][0]-i+f[st[top][0]]+h[st[top][0]]-h[i]+p[st[top][0]]);
        cnt=min(cnt,f[i]+i-h[i]+p[i]);
        st[++top][0]=i;
        st[top][1]=cnt;
    }
    printf("%lld",f[1]);
    return 0;
}

评论

xuruiyang
666@heqingyu
  • 2018-03-29 18:57:17