2017.5.15 COCI2011/2012 Contest#5

来源:互联网 发布:清风不语网络剧资源 编辑:程序博客网 时间:2024/06/07 09:54

A KRIŽALJKA

【分析】
这一题只要仔细看题目的话应该是简单的,也相信大家不是来看我怎么花式讲水题的,就直接贴代码了。

【代码】

#include <bits/stdc++.h>using namespace std;#define M 40char a[M],b[M];int n,m,f=1;int pos1,pos2;char mp[M][M];int main(){    scanf("%s",a+1);    scanf("%s",b+1);    n=strlen(a+1);    m=strlen(b+1);    for(int i=1;i<=m;i++){        for(int j=1;j<=n;j++)mp[i][j]='.';    }    for(int i=1;f&&i<=n;i++){        for(int j=1;f&&j<=m;j++){            if(a[i]==b[j]){                f=0;                pos1=j;                pos2=i;            }        }    }    for(int i=1;i<=n;i++)mp[pos1][i]=a[i];    for(int i=1;i<=m;i++)mp[i][pos2]=b[i];    for(int i=1;i<=m;i++){        for(int j=1;j<=n;j++)printf("%c",mp[i][j]);        puts("");    }    return 0;}

B EKO

【分析】
考虑到答案存在单调性,所以就直接二分咯。
想要1A的话还是要注意算md的时候有可能爆int。

【代码】

#include <bits/stdc++.h>using namespace std;#define ll long long#define M 1000005int a[M];int n,m;int l,r;int res;bool chk(int h){    ll hav=0;    for(int i=1;i<=n;i++){        if(a[i]<=h)continue;        hav+=a[i]-h;    }    return hav>=m;}int main(){    scanf("%d %d",&n,&m);    for(int i=1;i<=n;i++){        scanf("%d",&a[i]);        r=max(r,a[i]);    }    while(!(l>r)){        int md=1ll*(l+r)/2;        if(chk(md)){            res=md;            l=md+1;        }else r=md-1;    }    printf("%d\n",res);    return 0;}

C DNA

【分析】
知道题可以考虑贪心和dp,但是,我并没有找出容易的贪心做法,那就换一个路子,dp。
我们定义dp[i][j]表示将1~i全部变成j需要的最小个数。
那么转移方程也就比较容易推出了。
但是比赛的时候没有将这题1A,原因是RE了…

【代码】

#include<bits/stdc++.h>using namespace std;#define M 1000005int dp[2][M];//B 0;A 1 bool mk[M];char a[M];int n;int main(){    scanf("%d",&n);    scanf("%s",a+1);    for(int i=1;i<=n;i++){        bool f=(a[i]=='A');        dp[f][i]=min(dp[f][i-1],dp[!f][i-1]+1);        dp[!f][i]=min(dp[f][i]+1,dp[!f][i-1]+1);    }    printf("%d",dp[1][n]);    return 0;}

D RAZBIBRIGA

【分析】
花了半天时间看英文题似懂非懂。感谢小C的中文题意。
我们发现,想要组成这样一个首尾相连的矩形,唯一有用的只是一个单词的开头和结尾的字母。
既然有四个起点和终点,那么我们就枚举终态。
不过还要考虑到一些重复算的相同的部分。如何将他们去掉,就看大家各显神通了。

【代码】

#include <bits/stdc++.h>using namespace std;#define M 100005#define ll long longchar a[M][15];int n,m;ll ans;int cnt[28][28];int main(){    scanf("%d",&n);    for(int i=1;i<=n;i++)scanf("%s",a[i]+1);    m=strlen(a[1]+1);    for(int i=1;i<=n;i++){        int x=a[i][1]-'A';        int y=a[i][m]-'A';        cnt[x][y]++;    }    for(int i=0;i<26;i++){        for(int j=0;j<26;j++){            for(int k=0;k<26;k++){                for(int p=0;p<26;p++){                    int you[28][28];                    memset(you,0,sizeof(you));                    ll now=cnt[i][j];                    you[i][j]++;                    now*=1ll*(cnt[j][k]-you[j][k]);                    you[j][k]++;                    now*=1ll*(cnt[p][k]-you[p][k]);                    you[p][k]++;                    now*=1ll*(cnt[i][p]-you[i][p]);                    if(now<=0)continue;                    ans+=now;                }            }        }    }    cout<<ans<<endl;    return 0;}

E BLOKOVI

【分析】
比赛的时候完全没什么想法。直接敲了30分。
比赛结束后听jiedai大神的思路,感觉智商又下线了。
啦啦啦,我又回来了!

以下是sonytoy大神的证明

**我们假设已知当前积木i质量mass,之前所有积木质量M,
以积木i的左端点为原点,设i1块积木构成的整体的重心在X轴的坐标为x,x[0,2]
新的重心横坐标
NewCentre=Mx+1massM+mass=Mx+massM+mass
新的最右端
Right=Max(2,x+dp[i1])
所以
dp[i]=Max(2,x+dp[i1])Mx+massM+mass
=Max(2M+2mass,x(M+mass)+dp[i1](M+mass))MxmassM+mass
=Max((2x)M+mass,(x1)mass+dp[i1](M+mass))M+mass
可以发现,Max()中的两个式子,一个是单调递增,一个是单调递减的,均满足单调性,因此直接考虑x=0,2完全是可以的,换句话说,即一个是重心在左端点,一个是重心在右端点。所以答案是在这两个地方产生的。**

【代码】

#include <bits/stdc++.h>using namespace std;#define db double#define M 300005db ans,sum;int a[M];int n;int main(){    scanf("%d",&n);    for(int i=1;i<=n;i++)scanf("%d",&a[i]);    for(int i=n;i>1;i--){        sum+=a[i];        db Z=1.0*a[i]/sum;        ans=max(ans,max(ans+Z,2-Z));    }    printf("%.8f\n",ans);    return 0;}

F POPLOČAVANJE

【分析】
这题十分的奇怪,因为纯暴力可以有58分。这可是最后一道题啊。
关于字符串的题目,博主现在只有这几种方法:Hash、Trie树。因为我还没有对字符串继续深入学。
所以除了暴力,我还想到了Hash,可是这样复杂度就是O(nm),这样应该会超时。但是 很奇怪 过掉了。(加一些奇奇怪怪的优化 跑的居然比正解的AC自动机、后缀自动机还快)。
但我觉得不能超过正解,所以我还是将原始的代码贴出来。

【代码】

#include<bits/stdc++.h>#define usi unsigned int#define ll long longusing namespace std;#define M 305005#define P 233char a[M],b[5005];usi num[M],F[M];int n,m,ans;int mk[M];ll cnt;int main(){    scanf("%d %s %d",&n,a+1,&m);    F[0]=1;    for(int i=1;i<=n;i++)F[i]=F[i-1]*P;    for(int i=1;i<=n;i++)num[i]=num[i-1]*P+a[i];    while(m--){        scanf("%s",b+1);        int len=strlen(b+1);        usi res=0;        for(int i=1;i<=len;i++)res=res*P+b[i];        int w=n-len+1;        for(int i=1;i<=w;i++){            if(res==num[i+len-1]-num[i-1]*F[len])mk[i]++,mk[i+len]--;        }    }    for(int i=1;i<=n;i++)cnt+=mk[i],ans+=(!cnt);    printf("%d\n",ans);    return 0;}

这场比赛做的还是比较顺利的。两题1A,两题较快A掉,还有最后两题,花了不少时间。而且F题被一个学弟给血虐了……我感觉这其实暴露了一些问题:不是说他们天赋异禀,而是说他们比我们更踏实,不在意那些所谓的题数,而是把事情做精。虽然比他们的年龄大,但是还是要向他们学习。

原创粉丝点击