Test 3 for NOIP- Result for Day2

头大

这个暑假完就要去搞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] << " ";

}

代码同样短的吓人。

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值