noip模拟题 11.2

T1 神秘大门

【题目描述】

最近小K大牛经过调查发现,在WZland的最南方——WZ Antarctica 出现了奇怪
的磁场反应。为了弄清楚这一现象,小K 大牛亲自出马,来到了WZ Antarctica。
小K大牛发现WZ Antarctica 出现了一道神秘的大门。人总有好奇心,小K大牛想打开这扇神秘大门,看门的后面究竟是什么东西,但用尽什么办法也不能打开这扇门。
突然,门上出现了一些奇怪的字符。凭着敏锐的直觉,小K 认为这些符号就是打开这扇门的关键, 于是小K 抓紧时间开始研究这些符号。
经过一些时间的研究,小K 大牛发现这些符号其实是一串密码,只有破解了这个密码, 才能打开那扇神秘大门。这个密码十分简单,他给出了两个很长的字符串A 和B,你只需要判断B 是否在A 中出现过就可以了,当然如果B 在A中出现,那么你还需要输出B 的字符在A 中依次出现的位置。这里解释一下B 在A 中出现的概念,设A=S1S2…SN,B= T1T2…TM,如果存在一组数K:K1<K2<…<KM,使得B=SK1SK2…SKM,那么就可以认为B 在A 出现过。比如说A=sdfesad, B=sfsad,那么B 在A 中出现过,因为B 中的字符在A中依次出现的位置为1 3 5 6 7。
这个解密过程实在太简单了,于是小K 大牛就将这个任务交给了你。由于小K大牛十分着急,他只给了你1s 的时间。

【输入】

输入数据包含2 行,分别包含一个字符串,第一行输入的是字符串A,第二行输入的是字符串B。

【输出】

第一行输出一个字符串“Yes”或“No”,如果B 在A 中出现,那么输出“Yes”,否则输出“No”。
如果你的第一行输出“Yes”,那么在第接下来若干行你需要输出一组数K,使得B=SK1SK2…SKM,每行一个数;否则第二行为空。如果存在多组数据满足条件,你需要输出字典序最大的一组。

【输入输出样例1】

输入:
sdfesad
sfsad

输出:
Yes
1
3
5
6
7

【输入输出样例2】

输入:
abcdef
acdefg

输出
No

水题,一开始想的是用两个指针对应 A B 串的下标,枚举即可。需要注意的是要输出字典序最大的,所以从后往前枚举即可。
代码:

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
char A[1000005],B[1000005];
int ans[1000005],cnt;
int main()
{
    freopen("door.in","r",stdin);
    freopen("door.out","w",stdout);
    scanf("%s",A);
    scanf("%s",B);
    int lena=strlen(A),lenb=strlen(B);
    int i=lena-1,j=lenb-1;
    while(i>=0)
    {
        if(A[i]==B[j])
        {
            i--;
            j--;
            ans[++cnt]=i+2;
        }
        else i--;
        if(j==-1)
        {
            printf("Yes\n");
            for(int k=cnt;k>=1;k--)
                printf("%d\n",ans[k]);
            return 0;
        }
    }
    printf("No");
    return 0;
}

T2 集结蚂蚁

【题目描述】

雄心勃勃的企业家达伦·克劳斯发现了皮姆博士有关缩小原子间距离的公式并研发出新一代微型“黄蜂战士”,皮姆博士担忧武器会引发不可挽回的后果,于是找到斯科特并使他成为了新一代“蚁人”。正逢克劳斯与外商交易黄蜂战衣的那天,斯科特受命前往摧毁黄蜂战衣并销毁数据,然而一个人的力量是渺小的,斯科特需
要走入一个巨大的蚁穴去召唤蚂蚁与他共同作战。
蚁穴是一个巨大复杂的地带,由n 行m 列组成,每个偶数行存在至少一个蚂蚁聚集地,同一行的不同蚂蚁聚集地以一堵墙隔开,每个蚂蚁聚集地的大小为Si;每个奇数行存在连接相邻偶数行中蚂蚁聚集地的路径,一个蚂蚁聚集地可能有多条路径可以到达。
蚁人可从蚁穴的第一行任何一路口出发,由于时间紧迫,蚁人只能向下一行走,在这种情况下,蚁人希望你能告诉他如何使经过的蚂蚁聚集地大小之和最大,从而召唤最多的蚂蚁。
这里写图片描述

【输入】

第1 行包含两个用空格隔开的整数n,m,意义见描述。
第2 到n+1 行,每行m 个字符(无间隔)且仅存在0 和1:同一偶数行中连续x 个0 组成一个大小为x 的蚂蚁聚集地,1 为墙体;奇数行中0 表示蚁人可以从此处通过。

【输出】

对于每组数据输出一个整数,表示经过路径中最大聚集地之和(不包含聚集地之间的路径)。若蚁人无法到达最后一行则请输出“-1”。

【输入样例】

10 10
1111101111
1100001011
1101111111
1100000101
1110110111
1000110001
1101111011
1101000011
1101011111
1101010001

【输出样例】

17

【样例解释】

这里写图片描述

【数据规模】

对于20%的数据,n≤20,m≤20
对于50%的数据,n≤20,m≤100
对于100%的数据,n≤5000,m≤2000,保证n 是一个偶数,路径的数量不多于1×10^6

不难想到往下dp,还是很好做的。有一点要注意,到达偶数行时,可以召唤整个蚂蚁聚集地的蚂蚁,而不是走的路径,所以要预处理一下,否则要 T。有大神用建图做。
好吧这题我被卡常了,T 了两个点。生平第一次被卡常,很不爽。
代码:

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int dp[5001][2001],n,m,tmp[2001];
int map[5001][2001];
int main()
{
    freopen("ant.in","r",stdin);
    freopen("ant.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        bool tttt=false;
        if(i&1==1)tttt=true;
        getchar();
        for(int j=1;j<=m;j++)
        {
            char c;
            scanf("%c",&c);
            if(c=='1')
                map[i][j]=-1;
            else
            {
                if(tttt==false)
                    map[i][j]=1;
                else map[i][j]=0;
            }
        }
    }
    memset(dp,128,sizeof(dp));
    for(int i=1;i<=m;i++)
        if(map[1][i]==0)
            dp[1][i]=0;
    for(int i=2;i<=n;i++)
    {
        int tt=-9999,now=-9999,tot=0;
        for(int j=1;j<=m;j++)
        {
            if(map[i][j]==-1)
            {
                if(tt>0)
                {
                    dp[i][j-1]=now+tot;
                    tot=0;
                    now=-9999;
                    tt=-9999;
                    continue;
                }
                tot=0;
                continue;
            }
            if(map[i][j]==1)
                tot++;
            if(dp[i-1][j]>=now)
            {
                now=dp[i-1][j];
                tt=j;
            }
            if(j==m&&tt)
            {
                if(map[i][j])
                    dp[i][j]=now+tot;
                else dp[i][j-1]=now+tot;
            }
        }
        for(int j=m;j>=1;j--)
            if(map[i][j]!=-1)
                dp[i][j]=max(dp[i][j],dp[i][j+1]);
    }
    int ans=-99,l;
    for(int i=1;i<=m;i++)
    //  if(dp[n][i]!=n)
            ans=max(ans,dp[n][i]);
    if(ans<0) printf("-1");
    else printf("%d",ans);
    return 0;
}

T3 计数

【题目描述】

我们都爱奎奎,最近奎奎给大家出了一道题。
他告诉了我们一个n*m 的矩阵点,在这个矩阵中的点可以连接成很多线,求长度等于某一长度的线的条数。

数论学的不好。
我的想法是先打一个表。数据范围是:N<=1000000000;M<=1000000000;T<=100
所以打一个 1…q 的表,内容是 i*i ,大概需要32000的空间,然后每输入一个数,枚举表中的内容,ans+ 就行。另外还加了优化。
但不知为何,要崩溃,访问无效内存…
崩溃代码:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int ping[1000000],ans[101];
int main()
{
    freopen("amount.in","r",stdin);
    freopen("amount.out","w",stdout);
    int n,m,t,cnt=0;
    for(int i=1;i*i<=1000000000;i++)
        ping[i]=i*i;
    scanf("%d%d%d",&n,&m,&t);
    while(t--)
    {
        int x;
        scanf("%d",&x);
        ans[++cnt]+=m*(n-x)+(m-x)*n;
        int q=x*x;
        int minx=lower_bound(ping+1,ping+31624,q)-ping-1;
        int low=0x7f7f7f7f;
        for(int i=1;ping[i]<low;i++)
        {
            int tmp=q-ping[i];
            for(int j=minx;j;j--)
            {
                if(tmp<ping[j])
                {
                    minx=j+1;low=ping[j+1];
                    break;
                }
                else if(tmp==ping[j])
                {
                    int op=i;
                    int cp=j;
                    ans[cnt]+=(n-op)*(m-cp)*2+(n-cp)*(m-op)*2;
                    minx=j;
                    low=ping[j];
                    break;
                }
            }
        }
    }
    for(int i=1;i<=cnt;i++)
        printf("%d ",ans[i]);
    return 0;
}

有人知道哪里崩溃了吗??求助。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值