Test 3 for NOIP- Result for Day2

来源:互联网 发布:条码生成器软件下载 编辑:程序博客网 时间:2024/06/05 18:09

头大

这个暑假完就要去搞NOIP了。。。

暑假55天也就20次测试。。。为防万一我还是每次测试玩都写个总结。。


。。。别问我为什么我没有给Day1的题目。。。三道水题我被坑的只有10分。。。。。。本来可以100多的。。
要不是这次几乎集体划水我的这个分只可能算垫底。(No.8)

Day2 (70/300)

T1 Hello(30/100)

题目背景
SOURCE:NOIP2015-SHY-1

题目描述
Alice 和 Bob 有一个长度为2n的数。现在他们要在这个数字上玩游戏。他们分别要从 2n 个位中取出 n 个位组成自己的幸运值。每一回合,Alice 或 Bob 把数字最左边的那一位拿来放在自己幸运值

的最末位。在第 i 轮操作过后,被选取的数位(原数的第i位)会从原数中消失。现在 Alice 和 Bob 想要使得他们两个幸运值的和尽可能大。请求出这个值。

输入格式
第一行一个整数 n ,意为幸运值的长度。
第二行一个长度为 2n 的数字,表示原数。

输出格式
一个整数为幸运值的和的最大值。

样例数据 1
输入  [复制]
2
1234

输出
46

备注
【样例说明】
Alice 取 1、2 位。Bob 取 3、4 位。幸运值分别为 12 和 34 ,和为 46 。

【数据范围】
对 30% 的输入数据 : n≤10;
对 100% 的输入数据 : n≤18,原数与幸运值均允许前缀 0 的存在。

MY.CPP

#include<iostream>#include<iomanip>#include<cstdio>#include<cstdlib>#include<algorithm>#include<cmath>#include<string>#include<cstring>#include<ctime>using namespace std;int n,num[40],pos[40],ans[20];int alice[20],bob[20],alicei=0,bobi=0;char c;bool visit[40];struct node{    int num;    int pos;}deal[40];bool comp(node a,node b){    if(a.num==b.num)    return a.pos < b.pos;    return a.num > b.num;}void find(){    for(int i=1;i<=2*n;i++)    {        if(deal[i].pos<=alicei+n+1 && alicei<deal[i].pos && !visit[deal[i].pos] )        {            visit[deal[i].pos] = true;              if(bobi<=n)            for(int j=alicei+1;j<=deal[i].pos;j++)            {                if(!visit[j])                {                    bobi += 1;                    visit[j] = true;                    bob[bobi] = num[j];                }            }            alicei += 1;            alice[alicei] = deal[i].num;        }    }}int main(){    freopen("hello.in","r",stdin);    freopen("hello.out","w",stdout);    cin >> n;    for(int i=1;i<=2*n;i++)    {        cin >> c;        num[i] = c-'0';        deal[i].num = num[i];        deal[i].pos = i;    }    sort(deal+1,deal+2*n+1,comp);    find();    if(alicei!=n)    for(int i=1;i<=2*n,alicei<n;i++)        if(!visit[i])        {            alicei+=1;            alice[alicei] = num[i];        }    if(bobi!=n)    for(int i=1;i<=2*n,bobi<n;i++)        if(!visit[i])        {            bobi+=1;            bob[bobi] = num[i];        }       for(int i=1;i<=n;i++)    {        ans[i-1] += (alice[i]+bob[i])/10;        ans[i] += (alice[i]+bob[i])%10;    }    if(ans[0])  cout << ans[0];    for(int i=1;i<=n;i++)   cout << ans[i];}

题解却mdzz又是动态规划,而且也是不难想的那种,害得我还慢慢推了半天只过了30%。。。周日必须补动态规划了(其它时间我在预习高二。。)

STD.CPP

#include<iostream>#include<iomanip>#include<cstdio>#include<cstdlib>#include<algorithm>#include<cmath>#include<string>#include<cstring>#include<ctime>using namespace std;int n,num[40];unsigned long long dp[20][20];char c;int main(){    freopen("hello.in","r",stdin);    freopen("hello.out","w",stdout);    memset(dp,0,sizeof(dp));    cin >> n;    for(int i=1;i<=2*n;i++)    {        cin >> c;        num[i] = c-'0';        if(i<=n)        {            dp[i][0] = num[i-1]*10 + num[i];            dp[0][i] = num[i-1]*10 + num[i];        }    }    dp[0][0] = 0;    for(int i=0;i<=n;i++)    for(int j=0;j<=n;j++)    {        if(i!=n)dp[i+1][j] = max(dp[i+1][j] , dp[i][j] + num[i+j+1]*(long long)pow(10,n-i-1));        if(j!=n)dp[i][j+1] = max(dp[i][j+1] , dp[i][j] + num[i+j+1]*(long long)pow(10,n-j-1));      }       cout << dp[n][n];}

这题的动归实际上更简单。。。

T2 Rect(10/100)

题目背景
SOURCE:NOIP2015-SHY-1

题目描述
给定一个由数字(0-9)构成的字符串 s 。我们可以由此定义出 size(s) * size(s) 大小的矩阵 b ,其中 b[i][j] = s[i] * s[j] ;请问在这个矩阵 b 中,有多少子矩形满足其中的 b[i][j] 的和为另一个给定的数字 a 。

输入格式
第一行一个整数 a 。
第二行字符串 s 。

输出格式
输出一个整数表示满足条件的子矩形数。

样例数据 1
输入  [复制]

10
12345
输出

6
备注
【样例说明】
b矩阵为:
01 02 03 04 05
02 04 06 08 10
03 06 09 12 15
04 08 12 16 20
05 10 15 20 25

和为10的子矩形有:

(1)
01 02 03 04

(2)
01
02
03
04

(3)
04 06

(4)
04
06

(5)
10

(6)
10

以上共六个。

【数据范围】
对 10% 的输入数据 :size(s)≤10 ;
对 30% 的输入数据 :size(s)≤100 ;
对 100% 的输入数据 :0≤a≤1000000000,size(s)≤4000 。

MY.CPP

#include<iostream>#include<iomanip>#include<cstdio>#include<cstdlib>#include<algorithm>#include<cmath>#include<string>#include<cstring>#include<ctime>using namespace std;int n,ni;long long ans=0;unsigned long long ai;unsigned long long bx[4005],by[4005];char c[4005];int main(){    freopen("rect.in","r",stdin);    freopen("rect.out","w",stdout);    cin >> ai;    gets(c);    gets(c);    n = strlen(c);    int flag = 1;    for(int i=0;i<n;i++)    {        bx[i+1] = bx[i]+c[i]-'0';        by[i+1] = by[i]+c[i]-'0';    }    for(int i=1;i<=n;i++)      for(int j=i;j<=n;j++)        for(int a=i;a<=n;a++)          for(int b=a;b<=n;b++)            if((bx[j]-bx[i-1])*(bx[b]-bx[a])==ai)                ans += 1;    cout << ans;}

连打暴力后来发现都打错了害得30分的暴力分只得了十分。。。而且题解也不难想。。。我的脑子停机了吗。。
枚举横行与A相除得除数,再在纵行里枚举。就能避免n^4的时间复杂度。

STD.CPP

#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>#include<cctype>#include<cmath>#include<ctime>#include<queue>#include<map>using namespace std;char s[4005];int n;int sum[4005][4005],cnt[40005];int aim,ans,all;int main(){    //freopen("lx.txt","r",stdin);    cin>>aim>>s+1;    n=strlen(s+1);    for(int i=1;i<=n;++i)    {        long long res=0;        for(int j=i;j<=n;++j)        {            res+=s[j]-'0';            sum[i][j]=res;            cnt[res]++;            all++;        }    }    for(int i=1;i<=n;++i)        for(int j=i;j<=n;++j)        {            if(!sum[i][j])              {                if(!aim)ans+=all;            }            else                 if(aim%sum[i][j]==0&&aim/sum[i][j]<4005*9)                    ans+=cnt[aim/sum[i][j]];        }    cout<<ans<<endl;    return 0;}

T3 Shortest(30/100)

题目背景
SOURCE:NOIP2015-SHY-3

题目描述
给定一张 n 个点的有向带权完全图,和一个数组 a[] ,请按顺序删除数组中的点,请求出在删除点 a[i] 以前,所有未删除点对之间的最短路的值的和。

输入格式
第一行一个整数 n ,表示点数;
接下来 n 行,每行 n 个数构成邻接矩阵,描述每条边的权值,保证 i 号点到 i 号点的权值为 0 ;
最后一行 n 个小于等于 n 的不同的数,描述数组 a[]。

输出格式
输出 1 行 n 个数,表示答案。

样例数据 1
输入  [复制]

4
0 3 1 1
6 0 400 1
2 4 0 1
1 1 1 0
4 1 2 3
输出

17 23 404 0
备注
【数据范围】
对 30% 的输入数据 :1≤n≤10 ;
对 100% 的输入数据 :1≤n≤500;0<权值≤100000 。

MY.CPP

#include<iostream>#include<cstdio>#include<cstdlib>#include<cmath>#include<ctime>#include<cctype>#include<cstring>#include<string>#include<algorithm>using namespace std;int n, s, cnt = 0;int stack[200050], hash[70000], check[70000];char c[5], num[20];void cint(int aq,int cnt){    int ans=0,i;    for(i=1;i<=cnt;i++)    {        if(hash[stack[i]])        {          int h1 = stack[i];          int h2 = aq;          if((h1&h2)==stack[i])            ans += hash[stack[i]];        }    }    cout << ans << endl;}bool comp(int a,int b){    return a>b;}int init(int cnt,int flag){    sort(stack+1,stack+cnt+1,comp);    if(flag)    cnt-=1;    for(int i=1;i<=cnt;i++)        check[stack[i]] = i;    return cnt;}int main(){    int y=0;    cin >> n;    while(n--)    {        int flag=0;        scanf("%s",c);  cin >> s;        if(c[0]=='a')   {hash[s]+=1;if(hash[s]==1)stack[++cnt]=s;}        else if(c[0]=='d')  {hash[s]-=1;if(hash[s]==0)stack[check[s]]=0,check[s]=0,flag = 1;}        else if(c[0]=='c')  {cint(s,cnt);y+=1;}        cnt = init(cnt,flag);    }}

这道题最恶心的是我用SPFA打了半天才能的暴力分,而最开始一直鄙视的Floyed确是正确解法。。。
。。。。。。
动态规划得好好补补了orz。

STD.CPP

//卧槽是Floyed#include<iostream>#include<iomanip>#include<cstdio>#include<cstdlib>#include<algorithm>#include<cmath>#include<string>#include<cstring>#include<ctime>using namespace std;int n;long long  a[505];long long  f[505][505],ans[505];int main() {    cin >> n;    for(int i=1;i<=n;i++)      for(int j=1;j<=n;j++)        cin >> f[i][j];    for(int i=1;i<=n;i++)        cin >> a[i];    for(int i=n;i>=1;i--)    {        for(int j=n;j>i;j--)          for(int k=n;k>i;k--)          {            f[a[i]][a[j]] = min(f[a[i]][a[j]],f[a[i]][a[k]]+f[a[k]][a[j]]);            f[a[j]][a[i]] = min(f[a[j]][a[i]],f[a[j]][a[k]]+f[a[k]][a[i]]);          }        for(int j=n;j>i;j--)          for(int k=n;k>i;k--)            f[a[j]][a[k]] = min(f[a[j]][a[k]],f[a[j]][a[i]]+f[a[i]][a[k]]);        for(int j=n;j>=i;j--)          for(int k=n;k>=i;k--)            ans[i] += f[a[j]][a[k]];    }    for(int i=1;i<=n;i++)   cout << ans[i] << " ";}

代码同样短的吓人。

好,好,学,习,动,态,规,划。