Test 8 for NOIP- Result for Day2

头大

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

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


Day2比Day1好一点。。可能是因为题简单点的缘故。。
坑爹的是因为做的是USACO的题,题解。。。全英文。。。我就算在成外待过看着也够呛。。

Day2 (130/300)

Bovine Genomics (40/100)

源文件:cownomics.cpp/c/pas
输入文件:cownomics.in
输出文件:cownomics.out
【题目大意】
农夫约翰最近发现他的有些奶牛会画画,刚刚学完小学生物的他立刻开始研究起了这些
奶牛的DNA。
具体的,约翰有N头会画画的奶牛,N头不会画画的奶牛,这些奶牛的DNA可以用M个
字符来描述,每个字符是A、C、G、T中的一个
比如说以下是N=3,M=8的一个示例:
位置: 1 2 3 4 5 6 7 8

会画画的牛1: A A T C C C A T
会画画的牛2: A C T T G C A A
会画画的牛3: G G T C G C A A

不会画画的牛1: A C T C C C A G
不会画画的牛2: A C T C G C A T
不会画画的牛3: A C T T C C A T

约翰发现,他只需要看[2,5]这个区间的DNA就可以知道一头牛会不会画画(也就是说,
没有一头会画画的牛的这个区间的DNA是和某一头不会画画的牛的这个区间的DNA相同的),
他相信一头牛是否会画画是由这个区间的DNA决定的,他称这样的区间为“决定区间”
现在给你所有牛的DNA,求最短的决定区间的长度。

【输入格式】
第一行两个数N,M(N<=500;M<=500)。
接下来N行,每行M个字符,描述N头会画画的牛的DNA。
接下来N行,每行M个字符,描述N头不会画画的牛的DNA。

【输出格式】
输出最短的决定区间的长度。

【样例输入】
3 8
AATCCCAT
ACTTGCAA
GGTCGCAA
ACTCCCAG
ACTCGCAT
ACTTCCAT
【样例输出】
4

【数据范围】
40% 的数据:N,M<=100。
100% 的数据:N,M<=500。

MY.CPP

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<iomanip>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
using namespace std;

int n,m;
char c[550];
int can[550][550],op[550];
int nod[550][550],ot[550];
int hash[550];

int loc(int x)
{
    int f = x%500+1;
    while(hash[f]&&hash[f]!=x)f=(f-1)%500+2;
    return f;
}

int main()
{
    scanf("%d%d",&n,&m);    gets(c);
    for(int i=1;i<=n;i++)
    {
        scanf("%s/n",&c);
        for(int j=0;j<m;j++)
        {
            if(c[j]=='A')can[i][j+1]=0;
            if(c[j]=='G')can[i][j+1]=1;
            if(c[j]=='C')can[i][j+1]=2;
            if(c[j]=='T')can[i][j+1]=3;
        }
    }
    for(int i=1;i<=n;i++)
    {
        scanf("%s/n",&c);
        for(int j=0;j<m;j++)
        {
            if(c[j]=='A')nod[i][j+1]=0;
            if(c[j]=='G')nod[i][j+1]=1;
            if(c[j]=='C')nod[i][j+1]=2;
            if(c[j]=='T')nod[i][j+1]=3;
        }
    }
    int flag1=0;
    for(int t=1;t<=m;t++)
    {
        memset(op,0,sizeof(op));
        memset(ot,0,sizeof(ot));
        int flag2=0;    int dd=0;
        if(flag1)break;
        for(int i=1;i<=n;i++)
        {
            dd=0;
            for(int j=1;j<=t;j++)
                dd += can[i][j]*(int)pow(4,j-1);    
            hash[loc(dd)]=dd;  op[i]=dd;
        }
        for(int i=1;i<=n;i++)
        {
            dd=0;
            for(int j=1;j<=t;j++)
                dd += nod[i][j]*(int)pow(4,j-1);    
            if(hash[loc(dd)]==dd){flag2=1;}
            ot[i]=dd;
        }
        if(flag2)
        {   

            for(int j=2;j<=m-t+1;j++)
            {
            int flag3=0;    
            memset(hash,0,sizeof(hash));    

              for(int i=1;i<=n;i++)
              {
                op[i] -= can[i][j-1];
                op[i] /= 4;
                op[i] += can[i][j+t-1]*(int)pow(4,t-1);
                hash[loc(op[i])]=op[i];
              }         
              for(int i=1;i<=n;i++)
              {
                ot[i] -= nod[i][j-1];
                ot[i] /= 4;
                ot[i] += nod[i][j+t-1]*(int)pow(4,t-1);
                if(hash[loc(ot[i])]==ot[i])
                  {flag3=1;}
              } 
              if(!flag3){cout<<t<<endl;return 0;}
            }           
        }   
        else {cout<<t<<endl;return 0;}
    }
}

一通乱搞加双重哈希搞到40分。
题解加了个二分优化。
不知道为什么不加二分竟然会runtime error。

STD.CPP

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<ctime>
#include<algorithm>
using namespace std;

int n,m;
bool vis[1000005];
char s[505],c[505];
unsigned long long a[505][505],b[505][505],t[505];
int hash(unsigned long long a){return a*37%1000007;}

int get(char x){
    if(x=='A')return 1;
    if(x=='C')return 2;
    if(x=='G')return 3;
    if(x=='T')return 4;
}

bool check(int x)
{
    for(int i=x;i<=m;i++)
    {
        memset(vis,0,sizeof(vis));
        int sign=0;
        for(int j=1;j<=n;j++)
            vis[hash(a[j][i]-a[j][i-x]*t[x])]=1;

        for(int j=1;j<=n;j++)
        {
            if(vis[hash(b[j][i]-b[j][i-x]*t[x])])
                {sign=1;break;}
        }
        if(sign)continue;
        return true;
    }
    return false;
}

int main()
{
    cin >> n >> m;
    t[0]=1;
    for(int i=1;i<=m;i++)   t[i]=t[i-1]*37;
    for(int i=1;i<=n;i++)
    {
        scanf("%s",s+1);
        for(int j=1;j<=m;j++)
            a[i][j]=(a[i][j-1]*37+get(s[j]));
    }
    for(int i=1;i<=n;i++)
    {
        scanf("%s",c+1);
        for(int j=1;j<=m;j++)
            b[i][j]=(b[i][j-1]*37+get(c[j]));
    }
    int l=0,r=m;
    while(l<r)
    {
        int mid=(l+r)>>1;
        if(check(mid))r=mid;
        else l=mid+1;
    }
    cout << l << endl;
    return 0;
}

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

T2 art (90/100)

源文件:art.cpp/c/pas
输入文件:art.in
输出文件:art.out

【题目大意】
奶牛贝茜是一位出色的画家,她按照这样的方式作画:
首先有一个N*N的矩形画布,初始每个格子的颜色都是0(表示尚未上色),有N^2种颜
色,编号分别为1~N^2,贝茜每次选择一种颜色,然后在画布上选一个矩形,这样重复N^2
次,把这个矩形都涂上这个颜色。
每种颜色只能用恰好一次,每次选择的矩形的四边都是平行于画布的四边的,而且同一
个位置如果多次上色,后涂的颜色会覆盖新涂的颜色。每次选的矩形,最大可以和整个画布
一样大,最小可以只有一个格子那么小。
比如说对于一个4*4的画布。她也许会首先用2号颜色画一个矩形:
2 2 2 0
2 2 2 0
2 2 2 0
0 0 0 0
之后也许会选择7号颜色来画一个矩形:
2 2 2 0
2 7 7 7
2 7 7 7
0 0 0 0
之后再用3号颜色画一个小一点的矩形:
2 2 3 0
2 7 3 7
2 7 7 7
0 0 0 0

现在给你画布最后的模样,请你算出有多少种颜色是有可能被首先使用的。

【输出格式】
第一行一个整数N(1<=N<=1000)。
接下来N行,每行N个数,描述一个画布。

【输出格式】
输出一个整数,表示有多少种颜色可能被首先使用。

【样例输入1】
4
2 2 3 0
2 7 3 7
2 7 7 7
0 0 0 0

【样例输出1】
14

【样例解释】
在第一个样例中,显然3要在7之后使用,而7要在2之后使用,而2是可能被首先使
用的,对于另外13种没有出现的颜色,我们可以认为它们是一开始被使用了,然后又被覆盖
了,因此它们也是可能首先被使用的。

【数据范围】
30%的数据:N<=5
50%的数据:N<=200
100% 的数据:N<=1000。

史上最神奇的事情:暴力可以拿到90%的分!!出题人真良心

MY.CPP

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<iomanip>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
using namespace std;

const int kkk=1000050;
int n,c,ans=0,num=0,hash[kkk],chek[kkk],stk[kkk];
int sum[kkk],map[1005][1005];
int lc[kkk],rc[kkk],uc[kkk],dc[kkk];

int main()
{
    memset(lc,127,sizeof lc);
    memset(uc,127,sizeof uc);
    cin >> n;
    for(int i=1;i<=n;i++)
      for(int j=1;j<=n;j++)
      {
        cin >> c;
        if(c)
        {
            map[i][j] = c;
            lc[c]=min(lc[c],j);
            rc[c]=max(rc[c],j);
            uc[c]=min(uc[c],i);
            dc[c]=max(dc[c],i);
            sum[c]++;
            if(!hash[c])
              {
                num++;stk[num]=c;hash[c]=1;
              }
        }   
      }
    ans = n*n;
    if(num==1){cout<<ans-1<<endl;return 0;}
    for(int i=1;i<=num;i++) 
    {
        int jud = (rc[stk[i]]-lc[stk[i]]+1)*(dc[stk[i]]-uc[stk[i]]+1);
        if(jud>sum[stk[i]])
        for(int x=lc[stk[i]];x<=rc[stk[i]];x++)
          for(int y=uc[stk[i]];y<=dc[stk[i]];y++)
            if(map[y][x]&&map[y][x]!=stk[i]&&!chek[map[y][x]])
              chek[map[y][x]]=1,ans--;            
    }
    cout << ans;
}

题解优化了一下统计

STD.CPP

#include<cstdio>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<algorithm>
#include<iomanip>
#include<iostream>
#include<cctype>
#define N 1000005
using namespace std;
int n,x,tot,top,sum,r[N],l[N],s[N],u[N],stack[N],a[1005][1005],b[1005][1005];
bool vis[N],w[N];
//---------------------
inline int Readint(){
    int i=0,f=1;char ch;
    for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
    if(ch=='-') f=-1,ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<1)+(i<<3)+ch-'0';
    return i*f;
}
//---------------------
int main()
{
    //freopen("art.in","r",stdin);
    //freopen("art.out","w",stdout);

    n=Readint();
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            x=Readint();
            a[i][j]=x;
            if(x!=0){
                tot++;
                if(!vis[x]){
                    stack[++top]=x;
                    vis[x]=true;
                }
                if(l[x]==0) l[x]=100000;
                if(s[x]==0) s[x]=100000;
                l[x]=min(l[x],j);
                r[x]=max(r[x],j);
                s[x]=min(s[x],i);
                u[x]=max(u[x],i);
            }
        }
    }
    if(top==1) cout<<n*n-1<<endl; 
    else{
        for(int i=1;i<=top;i++){
            int p=stack[i];
            b[s[p]][l[p]]++;
            b[s[p]][r[p]+1]--;
            b[u[p]+1][l[p]]--;
            b[u[p]+1][r[p]+1]++;
        }   

        for(int i=1;i<=n;i++)
          for(int j=1;j<=n;j++)
            b[i][j]+=b[i-1][j]+b[i][j-1]-b[i-1][j-1];

        for(int i=1;i<=n;i++)
          for(int j=1;j<=n;j++)
            if(b[i][j]>1 && !w[a[i][j]]) sum++,w[a[i][j]]=true;

        cout<<n*n-sum<<endl;
    }
    return 0;
}

T3 art2

源文件:art2.cpp/c/pas
输入文件:art2.in
输出文件:art2.out

【题目大意】
奶牛贝茜已经厌倦了二维的绘画,于是她想要画更抽象的一维画。
她的画板是一个长度为N的序列,一开始每个位置的颜色都是0,表示空白,她有N种
颜料,颜色编号分别为为1~N,每次她会选择一种颜料,然后选择一个区间,把这个区间的
所有位置全部涂成这个颜色(当然,后涂的颜色会覆盖先涂的颜色),她会进行恰好N次这样
的操作,每种颜料会且仅会用一次。
邪恶的奶牛月网想要抄袭贝茜的大作,她按这样的顺序作画:每次操作,她会选择一些
不相交的区间,然后分别给每个区间涂上某种颜色(同样地,后涂的颜色会覆盖先涂的颜色)
在整个过程中,每种颜色只能被用来涂不超过一个区间(不一定所有颜色都要用)。现在,月
网想知道,她至少需要多少次操作来完成她的计划?

【输入格式】
第一行一个整数N(N<=100000),接下来N行,每行一个整数,表示贝茜的画作中第i
个位置的颜色。

【输出格式】
输出月网要复制贝茜的画,最少需要的操作数(如果她无法完成,输出-1)。

【样例输入1】
7
0
1
4
5
1
3
3

【样例输出1】
2

【样例解释】
在第一组样例中,月网首先选择[2,5]和[6,7]这两个区间,分别涂上颜色1和3。
然后选择[3,3]和[4,4]这两个区间,分别涂上颜色4和5。
(当然也有其它方案,但都至少需要两次操作)
【数据范围】
30%的数据:N<=500
50%的数据:,N<=10000
100% 的数据:N<=100000。

我的没有参考价值,思路完全不对。(虽然卡过了一个点)。。
题解思路出奇的简单。。记录一下深度就行了。

STD.CPP

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<iomanip>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
using namespace std;

const int kkk=100050;

int n,c,ans=0,num=0,cnt=0;
int sum[kkk],map[kkk],stk[kkk];
int lc[kkk],rc[kkk];

int main()
{
    //freopen("art2.in","r",stdin);
    //freopen("art2.out","w",stdout);
    cin >> n;

    memset(lc,127,sizeof(lc));
    for(int j=1;j<=n;j++)
      {
        cin >> c;
        if(c)
        {
            map[j] = c;
            lc[c] = min(lc[c],j);
            rc[c] = max(rc[c],j);
        }   
      }
    for(int i=1;i<=n;i++)
    {
        if(!map[i])continue;
        if(lc[map[i]]==i)
        {
            stk[++cnt] = map[i];
            ans = max(ans,cnt);
        }
        if(rc[map[i]]==i)
        {
            if(stk[cnt]!=map[i]){cout<<-1<<endl;exit(0);}
            else stk[cnt]=0,cnt--;
        }
    }
    cout << ans << endl;
    exit(0);
}

感受:

现在做的模板题偏少而重思维的题更多了。。(这对于刚刚花了大量时间却也没怎么记住模板的我是个坏消息)感觉关于一道题的想法没以前那么多了。。
之前全心投入的时候每晚还要因为一点习惯问题被骂。。有时真的觉得老师父母都特别不可理喻,说我们这样是为了你好最后在一点小习惯上例如什么笔盖上啊扔垃圾啊说半天而且是在我正在冲刺的时候,被打断不说最后还要把我骂的在地上打滚才罢休,现在没劲了又开始鼓励我了然而我都快颓废了→_→。。这个暑假六科主课基本没怎么练习。开学考试药丸。
好吧发泄了一通还是要直面事实对不对总之先要熬过开学考试然后多刷刷题熬过11月得个好点的成绩然后看是冲省队还是把我那个Inside Out的坑给填了吧orz。
。。不过这个坑恐怕有点太大了。。
还是先多在网上刷题为重。。 For Rayark!

最后欢迎各位大佬评论或者怎么都行orz

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值