第二关——2007NOIP提高组

14:27:40 我习惯在包里藏一瓶百无聊赖,打发人间白云和苍狗设计睡着的未来。 ——《我的名字》焦迈奇

有一种悲伤 叫做期末考试有什么大不了的,你怕什么,它就考什么

期末考的差(划重点,要考),悲伤到连A+Bproblem都打不出来,就只好来写博客!!!

第一题  统计数字

http://219.153.61.2:9000/contest/239/problem/1076

这道题很简单,我用的是sort函数进行排序,然后再输出的。

悲伤到不能打字,话不多说放代码

#include
#define ll long long
using namespace std;
ll n,a[200009];
int main()
{
    scanf("%d",&n);
    for(ll i=1;i<=n;i++)
    scanf("%d",&a[i]);
    sort(a,a+n+1);
    ll m=a[1],s=1;
    for(ll i=2;i<=n;i++)
    {
        if(a[i]==m)s++;
        else
        {
            cout<" "<endl;
            m=a[i],s=1;
        }
    }
    cout<" "<endl;
    return 0;
 } 

14:51:10  江山如此多娇,引无数英雄竞折腰

我太难了!!!

第二题  字符串的展开   

http://219.153.61.2:9000/contest/239/problem/1077

题目简单易懂,代码思路简单。就是无限无限无限无限的if条件语句。(唉,成绩杀我)打的我真的是头晕转向。(唉)这道题虽然思路清晰明了,代码也简单,但是有许多许多许多许多细小的问题值得注意一下,要不然一个问题就会挖你10分20分的样子。(唉,期末什么期末,我不要放假,我不要成绩)

  • 注意开字符数组,不要看题目说的什么字符串就天真傻傻的去开个字符串,会超出范围,反正字符串跟字符数组差不多的用法。字符数组它不香吗,所以还是建议用字符数组。(专业手抖100年)(唉)!!!
  • if语句中的条件要写清楚,比如两边要同为小写或同为数字而且左边比右边小之类的,要理清楚什么时候是<,什么时候是>,什么时候该=。(唉,这点要注意,很重要)
  • p1决定字符形式,注意在p1=2时,小写转大写是只有小写才减的!!!数字不要剪,这里要加一个条件,而且再加条件之后要将if语句的位置调换一下(也可以在加条件的基础上再加一个条件),不然又会错一个点。

好了,康康代码吧!!!(唉)

#include
using
namespace std; char a[1000000]; int p1,p2,p3; int main() { cin>>p1>>p2>>p3; cin>>a; for(int i=0;i) { if(a[i]=='-'&&((a[i+1]>='0'&&a[i+1]<='9'&&a[i-1]>='0'&&a[i-1]<='9'&&a[i+1]>a[i-1])||(a[i+1]>='a'&&a[i+1]<='z'&&a[i-1]>='a'&&a[i-1]<='z'&&a[i+1]>a[i-1]))) { char s[1000000]; int o=0; for(int j=a[i-1]+1;j1];j++) { if(p1==3) for(int k=1;k<=p2;k++) s[++o]='*'; else if(p1==1||(j>='0'&&j<='9')) for(int k=1;k<=p2;k++) s[++o]=j; else if(p1==2) for(int k=1;k<=p2;k++) s[++o]=j-32; } if(p3==1) for(int j=1;j<=o;j++) cout<<s[j]; else for(int j=o;j>=1;j--) cout<<s[j]; } else cout<<a[i]; } return 0; }

15:40:44 害!!!

命啊!!!

第三题   矩阵取数游戏

https://www.luogu.com.cn/problem/P1005

这道题不能用简单的暴力做,如果这样做的话,只能得到20分。

这道题实际上是一道dp的题。

其次,因为数据极其的大,所以在比赛是打这道题的时候,只能使用高精度

有一个n×m的矩阵,对于第ii行,每次取走边缘的Ai,j,增加这一行的得分x,求n行的最大得分总和。因为落实每一行,所以行之间的关系是不大的。

fi,j=max{fi1,j+Ai1,j2mj+i1,fi,j+1+Ai,j+12mj+i1}

Ans=maxim{fi,i+Ai,i2m}

话不多说,上代码吧

#include
#define ll __int128
void print(ll x)
{
    if (x==0) return;
    if (x)print(x/10);
    putchar(x%10+'0');
}
int n,m;
ll ans,a[100],f[100][100],p[100]={1};
ll dp()
{
    memset(f,0,sizeof(f));
    for(int i=1;i<=m;i++)
    for(int j=m;j>=i;j--)
    f[i][j]=std::max(f[i-1][j]+p[m-j+i-1]*a[i-1],f[i][j+1]+p[m-j+i-1]*a[j+1]);
    ll maxn=-1;
    for(int i=1;i<=m;i++)
    maxn=std::max(maxn,f[i][i]+a[i]*p[m]);
    return maxn;
}
int main()
{
    for(int i=1;i<=90;i++) 
    p[i]=p[i-1]<<1;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        scanf("%d",a+j);
        ans+=dp();
    }
    if(ans==0) puts("0");
    else print(ans);
    return 0;
}

以上为懒人算法,考试上是过不去的,好吧。(不要轻易模仿)

以下为我后面那个大佬的高精度代码,感谢大佬给我版权。

#include 
using namespace std;

const int N=85,mod=10000;
int n,m;
int ar[N];

struct node{
    int p[505], len;
    node() {
        memset(p, 0, sizeof p);
        len = 0;
    }  
    void print() {
        printf("%d", p[len]);  
        for (int i = len - 1; i > 0; i--) {  
            if (p[i] == 0) {
                printf("0000"); 
                continue;
            }
            for (int k = 10; k * p[i] < mod; k *= 10) 
                printf("0");
            printf("%d", p[i]);
        }
    }
}f[N][N],base[N],ans;

node operator + (const node &a,const node &b){
    node c; c.len = max(a.len, b.len); int x = 0;
    for (int i = 1; i <= c.len; i++) {
        c.p[i] = a.p[i] + b.p[i] + x;
        x = c.p[i] / mod;
        c.p[i] %= mod;
    }
    if (x > 0)
        c.p[++c.len] = x;
    return c;
}

node operator * (const node &a,const int &b){
    node c; c.len = a.len; int x = 0;
    for (int i = 1; i <= c.len; i++) {
        c.p[i] = a.p[i] * b + x;
        x = c.p[i] / mod;
        c.p[i] %= mod;
    }
    while (x > 0)
        c.p[++c.len] = x % mod, x /= mod;
    return c;
}
node max(const node &a,const node &b){
    if (a.len > b.len)
        return a;
    else if (a.len < b.len)
        return b;
    for (int i = a.len; i > 0; i--)
        if (a.p[i] > b.p[i])
            return a;
        else if (a.p[i] < b.p[i])
            return b;
    return a;
}

inline void basetwo(){
    base[0].p[1]=1,base[0].len=1;
    for(int i=1;i<=m+2;i++){
        base[i]=base[i-1]*2;
    }
}

inline int read(){
    int p=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)) f*=(ch=='-')? -1:1,ch=getchar();
    do p=(p<<1)+(p<<3)+(ch^48),ch=getchar();
    while(isdigit(ch));
    return p*f;
}

int main(){
    n=read(),m=read();
    basetwo();
    while(n--){
        memset(f,0,sizeof f);
        for(int i=1;i<=m;i++) ar[i]=read();
        for(int i=1;i<=m;i++){
            for(int j=m;j>=i;j--){
                f[i][j] = max(f[i][j], f[i - 1][j] + base[m - j + i - 1] * ar[i - 1]); 
                f[i][j] = max(f[i][j], f[i][j + 1] + base[m - j + i - 1] * ar[j + 1]);
            }
        }
        node Max;
        for (int i = 1; i <= m; i++)
            Max = max(Max, f[i][i] + base[m] * ar[i]);
        ans = ans + Max; 
    }
    ans.print();
    return 0;
}

15:19:20 生亦我所欲也,死亦我所欲也(小朋友不要盲目背这句话哦)

暴风哭泣!!!

第四题   树网的核

http://219.153.61.2:9000/contest/239/problem/1079

这道题是关于树的!!!唉,学信奥=洗脑=“树学竞赛”

首先,有几个概念要搞清楚

路径:树网中任何两结点a,b都存在唯一的一条简单路径,用d(a,b)表示以a,b为端点的路径的长度,它是该路径上各边长度之和。我们称d(a, b)a,b两结点间的距离。

D(v,P)=min{d(v,u)}, u为路径P上的结点。

树网的直径:树网中最长的路径成为树网的直径。对于给定的树网TT,直径不一定是唯一的,但可以证明:各直径的中点(不一定恰好是某个结点,可能在某条边的内部)是唯一的,我们称该点为树网的中心。

偏心距ECC(F):树网T中距路径F最远的结点到路径FF的距离,即

ECC(F)=max{d(v,F),vV}

因为树方面的题主要是背模板,所以就直接上代码了。(唉)!!!

#include
using namespace std;
int top,n,s,head[100010],vet[100010],val[100010],nex[100010],a[100010],fa[100010],dis[100010];
bool f[100010];
void add(int u,int v,int c)
{
    nex[++top]=head[u];
    head[u]=top;
    vet[top]=v;
    val[top]=c;
}
void dfs(int u,int x)
{
    int e,v;
    for (e=head[u];v=vet[e],e;e=nex[e])
    if (v!=x)
    {
        fa[v]=u;
        dis[v]=dis[u]+val[e];
        dfs(v,u);
    }
}
void sy(int u,int x,int y)
{
    int e,v;
    for (e=head[u];v=vet[e],e;e=nex[e])
    if (v!=x&&!f[v])
    {
        a[y]=max(a[y],dis[v]-dis[u]);
        sy(v,u,y);
    }
}
int main()
{
    int x,y,z;
    scanf("%d%d",&n,&s);
    for (int i=1; i)
    {
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z),add(y,x,z);
    }
    dfs(1,0);
    int l=0,r=0;
    for (int i=1;i<=n;i++)
    if (dis[i]>dis[l])
    l=i;
    for (int i=1;i<=n;i++) 
    dis[i]=0;
    dfs(l,0);
    for(int i=1;i<=n;i++)
    if(dis[i]>dis[r]) 
    r=i;//两次dfs求直径
    fa[l]=0;//注意一定要把根的父亲重置为0,因为在第一次dfs中它是一个结点
    for (int i=r;i;i=fa[i])
    f[i]=1;
    for (int i=r;i;i=fa[i])
    sy(i,0,i);
    int ans=0,ss=9999999;
    for (int i=r;i;i=fa[i])
        for (int j=i;j;j=fa[j])
        {
            if(dis[i]-dis[j]>s)break;//优化
            ans=max(dis[j],dis[r]-dis[i]);//特殊点
            for (int k=i; k!=fa[j]; k=fa[k])
            ans=max(ans,a[k]);
            ss=min(ans,ss);
        }
    printf("%d\n",ss);
    return 0;
}

15:36:02煎熬,时间在这一刻停止了吗,过得好漫长啊,害!!!何时才能解脱

你可能感兴趣的:(第二关——2007NOIP提高组)