NOIP 提高组 2007

102 篇文章 1 订阅
77 篇文章 0 订阅

星空云的主机炸了,先来这里发一波

P1005 矩阵取数游戏

题目描述
帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数。游戏规则如下:
1.每次取数时须从每行各取走一个元素,共n个。m次后取完矩阵所有元素;
2.每次取走的各个元素只能是该元素所在行的行首或行尾;
3.每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值*2^i,其中i表示第i次取数(从1开始编号);
4.游戏结束总得分为m次取数得分之和。
帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。
输入输出格式
输入格式:
输入文件game.in包括n+1行:
第1行为两个用空格隔开的整数n和m。
第2~n+1行为n*m矩阵,其中每行有m个用单个空格隔开的非负整数。
数据范围:
60%的数据满足:1<=n, m<=30,答案不超过10^16
100%的数据满足:1<=n, m<=80,0<=aij<=1000
输出格式:
输出文件game.out仅包含1行,为一个整数,即输入矩阵取数后的最大得分。
输入输出样例
输入样例#1:
2 3
1 2 3
3 4 2
输出样例#1:
82
说明
NOIP 2007 提高第三题
高精+DP DP很好想,裸DP60分

#include<iostream>
#include<cstring>
#include<cstdio>

using namespace std;
#define MAXN 85

struct Bign{
    static const int Base=1000000;
    int a[100],len;
    Bign(){ len=1,a[0]=0; }
    Bign(int x){ len=1,a[0]=x; }
    Bign(const Bign &P){ *this = P; }

    Bign operator * (const int &p) const  {
        int x=0;
        Bign A= *this;
        for(int i=0;i<len;++i){
            A.a[i]=p*A.a[i]+x;
            x=A.a[i]/Base;
            A.a[i]%=Base;
        }
        if(x){
            A.a[len]=x;A.len++;
        }
        return A;
    }

    Bign operator + (const Bign &P) const {
        Bign A;
        int x=0,i;
        for(i=0;i<min(P.len,len);++i){
            A.a[i]=a[i]+P.a[i]+x;
            x=A.a[i]/Base;
            A.a[i]%=Base;
        }
        for(;i<len;++i){
            A.a[i]=a[i]+x;
            x=A.a[i]/Base;
            A.a[i]%=Base;
        }
        for(;i<P.len;i++) {
            A.a[i]=P.a[i]+x;
            x=A.a[i]/Base;
            A.a[i]%=Base;
        }
        A.len=max(P.len,len);
        if(x==1){ A.a[len]=1,++A.len; }
        return A;
    }

    bool operator > (const Bign &P) const {
        if(len > P.len) return true;
        if(len < P.len) return false;
        for(int i=len-1;i>=0;--i)
            if(a[i]>P.a[i]) return true;
            else if(a[i]<P.a[i]) return false;
        return false;
    }

    void Print(){
        printf("%d",a[len-1]);
        for(int i=len-2;i>=0;--i) printf("%06d",a[i]);
        printf("\n");
        return ;
    }
}dp[MAXN][MAXN],ans,pow[MAXN];
int a[MAXN][MAXN],n,m;

void PrePare(){
    pow[1]=2;
    for(int i=2;i<=m;++i) pow[i]=pow[i-1]*2;
    return ;
}

inline void read(int &x){
    x=0; int f=1; char c=getchar();
    while(c>'9'||c<'0'){ if(c=='-') f=-1; c=getchar(); }
    while(c>='0'&&c<='9'){ x=x*10+c-'0'; c=getchar(); }  x*=f;
}

Bign DP(int line){
    for(int i=0;i<m+1;++i)
        for(int j=m+1;j>i;--j){
            dp[i][j]=0;
            Bign POW = pow[m+i-j+1];
            Bign left=POW*a[line][i];
            Bign right=POW*a[line][j];
            if(i!=0) dp[i][j]=dp[i-1][j]+left;
            if(j!=m+1){
                right=right+dp[i][j+1];
                if(right>dp[i][j]) dp[i][j]=right;
            }
        }
    Bign ret=0;
    for(int i=0;i<=m;++i) if(dp[i][i+1] > ret) ret=dp[i][i+1];
    return ret;
}

int main(){
    read(n),read(m);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
            read(a[i][j]);
    PrePare();
    for(int i=1;i<=n;++i) ans=ans+DP(i);
    ans.Print();
    return 0;
}

P1097 统计数字

题目描述
某次科研调查时得到了n个自然数,每个数均不超过1500000000(1.5*10^9)。已知不相同的数不超过10000个,现在需要统计这些自然数各自出现的次数,并按照自然数从小到大的顺序输出统计结果。
输入输出格式
输入格式:
输入文件count.in包含n+1行;
第一行是整数n,表示自然数的个数;
第2~n+1每行一个自然数。
输出格式:
输出文件count.out包含m行(m为n个自然数中不相同数的个数),按照自然数从小到大的顺序输出。每行输出两个整数,分别是自然数和该数出现的次数,其间用一个空格隔开。
输入输出样例
输入样例#1:
8
2
4
2
4
5
100
2
100
输出样例#1:
2 3
4 2
5 1
100 2
说明
40%的数据满足:1<=n<=1000
80%的数据满足:1<=n<=50000
100%的数据满足:1<=n<=200000,每个数均不超过1500 000 000(1.5*109)
NOIP 2007 提高第一题

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 200010
int a[MAXN],n;

inline void read(int &x){
    x=0; int f=1; char c=getchar();
    while(c>'9'||c<'0'){ if(c=='-') f=-1; c=getchar(); }
    while(c>='0'&&c<='9'){ x=x*10+c-'0'; c=getchar(); }
    x*=f;
}

int main(){
    read(n);
    for(int i=1;i<=n;++i) read(a[i]);
    sort(a+1,a+n+1);
    int ans=1;
    for(int i=2;i<=n;++i){
        if(a[i]==a[i-1]) ++ans;
        else {
            printf("%d %d\n",a[i-1],ans);
            ans=1;
        }
    }
    printf("%d %d\n",a[n],ans);
    return 0;
}

P1098 字符串的展开

题目描述
在初赛普及组的“阅读程序写结果”的问题中,我们曾给出一个字符串展开的例子:如果在输入的字符串中,含有类似于“d-h”或者“4-8”的字串,我们就把它当作一种简写,输出时,用连续递增的字母或数字串替代其中的减号,即,将上面两个子串分别输出为“defgh”和“45678”。在本题中,我们通过增加一些参数的设置,使字符串的展开更为灵活。具体约定如下:
(1) 遇到下面的情况需要做字符串的展开:在输入的字符串中,出现了减号“-”,减号两侧同为小写字母或同为数字,且按照ASCII码的顺序,减号右边的字符严格大于左边的字符。
(2) 参数p1:展开方式。p1=1时,对于字母子串,填充小写字母;p1=2时,对于字母子串,填充大写字母。这两种情况下数字子串的填充方式相同。p1=3时,不论是字母子串还是数字字串,都用与要填充的字母个数相同的星号“*”来填充。
(3) 参数p2:填充字符的重复个数。p2=k表示同一个字符要连续填充k个。例如,当p2=3时,子串“d-h”应扩展为“deeefffgggh”。减号两边的字符不变。
(4) 参数p3:是否改为逆序:p3=1表示维持原来顺序,p3=2表示采用逆序输出,注意这时候仍然不包括减号两端的字符。例如当p1=1、p2=2、p3=2时,子串“d-h”应扩展为“dggffeeh”。
(5) 如果减号右边的字符恰好是左边字符的后继,只删除中间的减号,例如:“d-e”应输出为“de”,“3-4”应输出为“34”。如果减号右边的字符按照ASCII码的顺序小于或等于左边字符,输出时,要保留中间的减号,例如:“d-d”应输出为“d-d”,“3-1”应输出为“3-1”。
输入输出格式
输入格式:
输入文件expand.in包括两行:
第1行为用空格隔开的3个正整数,依次表示参数p1,p2,p3。
第2行为一行字符串,仅由数字、小写字母和减号“-”组成。行首和行末均无空格。
输出格式:
输出文件expand.out只有一行,为展开后的字符串。
输入输出样例
输入样例#1:
1 2 1
abcs-w1234-9s-4zz
输出样例#1:
abcsttuuvvw1234556677889s-4zz
输入样例#2:
2 3 2
a-d-d
输出样例#2:
aCCCBBBd-d
说明
40%的数据满足:字符串长度不超过5
100%的数据满足:1<=p1<=3,1<=p2<=8,1<=p3<=2。字符串长度不超过100
NOIP 2007 提高第二题
一遍AC的你看zui下面

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std; 
#define MAXN 100000
char s[MAXN],p[MAXN];
int p1,p2,p3;
inline bool Judge(char c){
    return c>='a'&&c<='z';
}
int main(){
    cin>>p1>>p2>>p3;
    scanf("%s",s+1);
    int len=strlen(s+1),cur=0,i=1;
    while(s[i]=='-') p[++cur]='-',i++;
    i--;
    while(i<len){
        ++i;

        if(s[i]!='-'){ p[++cur]=s[i]; continue; }
        if(s[i-1]>=s[i+1]){ p[++cur]=s[i]; continue; }
        if(Judge(s[i-1])&&!Judge(s[i+1])){ //such as d-9
            p[++cur]='-';
            continue;
        }
        if(!Judge(s[i-1])&&Judge(s[i+1])){//such as 9-o
            p[++cur]='-';
            continue;
        }
        if(s[i-1]==s[i+1]){ p[++cur]='-'; continue; }
        if(((int)s[i-1]==(int)s[i+1] +1)&&s[i]=='-') continue;//such as d-e

        int q=cur;
        if(p1==1&&Judge(s[i-1])&&Judge(s[i+1])){
            for(int k=((int)s[i-1])+1;k<(int)s[i+1];++k)
                for(int j=1;j<=p2;++j)
                    p[++cur]=s[i-1]+k-(int)s[i-1];
        }
        if(p1==2&&Judge(s[i-1])&&Judge(s[i+1])){
            for(int k=((int)s[i-1])+1;k<(int)s[i+1];++k)
                for(int j=1;j<=p2;++j)
                    p[++cur]=s[i-1]+k-(int)s[i-1]-32;
        }
        if(!Judge(s[i-1])&&!Judge(s[i+1])&&p1!=3){
            for(int k=((int)s[i-1])+1;k<(int)s[i+1];++k)
                for(int j=1;j<=p2;++j)
                    p[++cur]=s[i-1]+k-(int)s[i-1];
        }
        if(p1==3){
            for(int k=((int)s[i-1])+1;k<(int)s[i+1];++k)
                for(int j=1;j<=p2;++j)
                    p[++cur]='*';
        }
        // 翻转 q+1到cur 
        if(p3==2) reverse(p+1+q,p+cur+1);
    }
    for(int i=1;i<=cur;++i) putchar(p[i]);
    putchar('\n');
    return 0;
}

P1099 树网的核

题目描述
设T=(V, E, W) 是一个无圈且连通的无向图(也称为无根树),每条边到有正整数的权,我们称T为树网(treebetwork),其中V,E分别表示结点与边的集合,W表示各边长度的集合,并设T有n个结点。
路径:树网中任何两结点a,b都存在唯一的一条简单路径,用d(a, b)表示以a, b为端点的路径的长度,它是该路径上各边长度之和。我们称d(a, b)为a, b两结点间的距离。
  D(v, P)=min{d(v, u), u为路径P上的结点}。
树网的直径:树网中最长的路径成为树网的直径。对于给定的树网T,直径不一定是唯一的,但可以证明:各直径的中点(不一定恰好是某个结点,可能在某条边的内部)是唯一的,我们称该点为树网的中心。
偏心距ECC(F):树网T中距路径F最远的结点到路径F的距离,即
ECC(F)=max{d(v, F),v∈V}
任务:对于给定的树网T=(V, E, W)和非负整数s,求一个路径F,他是某直径上的一段路径(该路径两端均为树网中的结点),其长度不超过s(可以等于s),使偏心距ECC(F)最小。我们称这个路径为树网T=(V, E, W)的核(Core)。必要时,F可以退化为某个结点。一般来说,在上述定义下,核不一定只有一个,但最小偏心距是唯一的。
下面的图给出了树网的一个实例。图中,A-B与A-C是两条直径,长度均为20。点W是树网的中心,EF边的长度为5。如果指定s=11,则树网的核为路径DEFG(也可以取为路径DEF),偏心距为8。如果指定s=0(或s=1、s=2),则树网的核为结点F,偏心距为12。
这里写图片描述
输入输出格式
输入格式:
输入文件core.in包含n行:
第1行,两个正整数n和s,中间用一个空格隔开。其中n为树网结点的个数,s为树网的核的长度的上界。设结点编号以此为1,2,……,n。
从第2行到第n行,每行给出3个用空格隔开的正整数,依次表示每一条边的两个端点编号和长度。例如,“2 4 7”表示连接结点2与4的边的长度为7。
输出格式:
输出文件core.out只有一个非负整数,为指定意义下的最小偏心距。
输入输出样例
输入样例#1:
5 2
1 2 5
2 3 2
2 4 4
2 5 3
输出样例#1:
5
输入样例#2:
8 6
1 3 2
2 3 2
3 4 6
4 5 3
4 6 4
4 7 2
7 8 3
输出样例#2:
5
说明
40%的数据满足:5<=n<=15
70%的数据满足:5<=n<=80
100%的数据满足:5<=n<=300,0<=s<=1000。边长度为不超过1000的正整数
NOIP 2007 提高第四题

//炒鸡不想做题,Ctrl+C、V  Ctrl+Shift+R
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 310
#define inf 999999
int G[maxn][maxn];
int main() {
    int n,s,ans=inf;
    scanf("%d%d",&n,&s);
    memset(G,inf,sizeof(G));
    for(int i=1;i<n;i++) {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        G[u][v]=G[v][u]=w;
    }
    for(int k=1;k<=n;k++) {
        G[k][k]=0;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                G[i][j]=min(G[i][j],G[i][k]+G[k][j]);
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(G[i][j]<=s) {
                int x=0;
                for(int k=1;k<=n;k++)
                    x=max(x,(G[i][k]+G[j][k]-G[i][j])>>1);
                ans=min(ans,x);
            }
    printf("%d",ans);
    return 0;
}

这里写图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七情六欲·

学生党不容易~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值