Test 4 for NOIP- Result for Day2

头大

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

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


终于在经过两周的煎熬后我终于能考好一次了。。莫名感动(可能是吧)
据曾老说这次给我们出题的是上一届的(noi还是noip?)金牌选手给我们出的,然后三个题的背景都不一样。。。【COCI AKCIJA,Codechef STDYTAB,CEOI BOARD】看着也是一脸懵逼。
不过这个分还是没上200,如果是110来计的话就能上270了还是不错,可以给原来成外的装个逼(hh)

Day2 (166/300)

T1 Bookstore(100/100)

题目背景
SOURCE:NOIP2016-RZZ-2 T1

题目描述
在遥远的汪星球,小W开了一家书店。

这家书店推出促销活动,即每次顾客可以选择三本书,然后可以免去其中最便宜的那本书的价格(也就是只需要支付最贵的两本书的价格之和的钱,就能买到这三本书)。当然,如果顾客选择的书不足三本,那么就只能付全部的价钱了。

现在,有一个顾客挑选了 n 本书,这个顾客想要知道,自己最少付多少钱可以买到全部的书?

输入格式
输入 n+1 行,第一行一个整数 n ,表示顾客要买的书的本书。
接下来 n 行,每行一个整数,表示每本书的价钱。

输出格式
输出一行,表示顾客最少要付多少钱。

样例数据 1
输入  [复制]

4
3
2
3
2
输出

8
备注
【数据规模与约定】
对于 50% 的数据,n≤2000。
对于 100% 的数据,1≤n≤100000,1≤ci≤100000。

智障暴力题。不过当时做完我还很不放心的回去检查了好几遍。。被T1坑得怕了。
每次比赛总有人被T1坑。

STD.CPP

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

long long n=0,a[100005],ans=0;

int main()
{
    freopen("bookstore.in","r",stdin);
    freopen("bookstore.out","w",stdout);    
    memset(a,0,sizeof(a));
    cin >> n;
    for(int i=1;i<=n;i++)   
    {
        cin >> a[i];
        ans += a[i];
    }
    sort(a+1,a+n+1);
    while(n-2>=0)
    {
        ans -= a[n-2];
        n-=3;
    }
    cout << ans;
}

T2 Table(60/100)

题目背景
SOURCE:NOIP2016-RZZ-2 T2

题目描述
给定一个 n×m 的矩阵,行列均从 1 开始标号。

一个矩阵被认为是稳定的,当且仅当对于任意的 2≤i≤n,第 i 行的数的和不小于第 i−1 行的数的和,且最后一行的数的和小于等于 m ,并且要求矩阵中所有的元素都是非负的。

求所有 n×m 的稳定矩阵的方案数,答案对 109 取模。

输入格式
第一行一个整数 T ,表示数据组数。
每组数据一行两个整数 n,m 。

输出格式
输出 T 行,每行一个整数,表示方案数。

样例数据 1
输入  [复制]

3
1 1
2 2
2 3
输出

2
25
273
备注
【数据规模与约定】
对于 30% 的数据,n,m≤3。
对于 60% 的数据,n,m≤50。
对于 100% 的数据,1≤n,m≤2000;1≤T≤10。

MY.CPP

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

int n,m,t,ans;
int dp1[2005][2005],dp2[2005][2005]; 

const int maxx = 1000000000;
//   dp1[当前个数][当前总合]=方案数        dp2[当前行数][当前总合]=方案数 
int main()
{

    freopen("table.in","r",stdin);
    freopen("table.out","w",stdout);

    cin >> t;
    while(t--)
    {
        memset(dp1,0,sizeof(dp1));
        memset(dp2,0,sizeof(dp2));

        cin >> n >> m;
        for(int i=0;i<=m;i++)
            dp1[1][i] = 1;

        for(int i=2;i<=m;i++)
          for(int j=0;j<=m;j++)
            for(int k=0;k<=j;k++)
            {
                dp1[i][j] += dp1[i-1][j-k];
                dp1[i][j] %= maxx;
            }

        for(int i=0;i<=m;i++)
          dp2[1][i] = dp1[m][i];

        for(int i=2;i<=n;i++) 
          for(int j=0;j<=m;j++)     
            for(int k=0;k<=j;k++) 
            {
                dp2[i][j] += (dp2[i-1][k]*dp1[m][j]);
                dp2[i][j] %= maxx;
            }

        for(int i=0;i<=m;i++)
        {
            ans += dp2[n][i];
            ans %= maxx;
        }

        cout << ans << endl;
        ans = 0;
    }
}

头一次正确地使用了Dp。。两个Dp一个预处理一个递推答案,以n^3的时间复杂度过了60%而且事后只需要优化就能得标答也是把我也吓一跳。
Dp真是一个神奇的东西。
题解就是用前缀和等各种方法把n^3的时间复杂度降成了n^2。

STD.CPP

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<cstring>
#include<string>
#include<cctype>
using namespace std;
const int mod=1e9;
int n,m,T,dp[2001][2001],c[4002][4002];
//---------------------
inline int Readint()
{
    int i=0,f=1; char ch;
    for(ch=getchar();(ch<'0'||ch>'9');ch=getchar());
    for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<1)+(i<<3)+ch-'0';
    return i*f;
}
//---------------------
int main()
{
    //freopen("table.in","r",stdin);
    //freopen("table.out","w",stdout);

   for(int i=0;i<=4001;i++) c[i][0]=1,c[i][i]=1;
   for(int i=1;i<=4001;i++)
     for(int j=1;j<=i;j++){
        c[i][j]=c[i-1][j-1]+c[i-1][j];
        c[i][j]%=mod;
     }
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        memset(dp,0,sizeof(dp));

        for(int i=0;i<=m;i++) dp[0][i]=1;
        for(int i=1;i<=n;i++){
          for(int j=0;j<=m;j++){
            long long now=dp[i-1][j];
            now=(now*c[j+m-1][m-1])%mod;
            if(j) dp[i][j]=dp[i][j-1]+now;
            else dp[i][j]=now;
            dp[i][j]=dp[i][j]%mod;
          }
        }
        cout<<dp[n][m]<<endl;
    }
    return 0;
}

T3 Board(6/100)

题目背景
SOURCE:NOIP2016-RZZ-2 T3

题目描述
给出这样一棵“二叉树”:

每个节点有左右两个儿子,并如下定义每个节点的高度:假设父亲节点的高度为 h ,那么他的两个儿子的节点的高度都是 h + 1 ,相同高度的所有节点称作一层。
每个节点的左儿子的子树都在右儿子的子树的左边,每一层相邻的两个节点之间有一条边。
下面是一个例子:
奇怪的二叉树
每一条图上的路径用一个字符串表示,字符串中的每一个字符表示一个移动。字符仅包含如下五种:

1:表示移动到当前节点的左儿子
2:表示移动到当前节点的右儿子
U:表示移动到当前节点的父亲节点
L:表示移动到当前节点同层的左边的节点(保证当前节点在这一层中不是最左边的节点)
R:表示移动到当前节点同层的右边的节点(保证当前节点在这一层中不是最右边的节点)
用一条路径来表示这条路径的终点,例如路径:221LU 就表示上图中的节点 A 。

给出两条路径,你的任务是求出着两条路径的终点之间的最短路。

输入格式
输入两行,每行一个字符串,分别表示两条路径。

输出格式
输出一行一个整数,表示能得到的串的总数。

样例数据 1
输入  [复制]

221LU
12L2
输出

3
备注
【数据规模与约定】
用 D 表示所有经过的节点中,深度最大的节点的深度;S 表示输入字符串的最大长度。
对于 10% 的数据,D≤10。
对于 30% 的数据,D≤50。
对于 50% 的数据,D≤1000。
对于 70% 的数据,D≤20000。
对于 100% 的数据,D≤100000;S≤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);
    }

}

一开始看见二叉树三个字我以为T3又是送。
看了半个小时后。。。坚决放弃。(我以为可以算出每个数的值结果深度可达100000连高精度都撑不住2^100000的巨大数字。)
别问我那3个点我是怎么过的。我也不知道。。orz
话说这次给的测试点真的多。。。50个。。中欧人这么有时间出数据?

STD’.CPP

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
using namespace std;
const int Maxn=1e5+50;
int BITA[Maxn],BITB[Maxn],nowbitA=1,nowbitB=1,_;
char ch[Maxn];

inline void delA(int nowbit,int val)
{
    if(val==1)
    {
        if(BITA[nowbit]==1)
        {
            BITA[nowbit]=0;
            return;
        }
        else
        {
            BITA[nowbit]=1;
            delA(nowbit-1,val);
        }
    }
    else
    {
        if(BITA[nowbit]==0)
        {
            BITA[nowbit]=1;
            return;
        }
        else
        {
            BITA[nowbit]=0;
            delA(nowbit-1,val);
        }
    }
}

inline void delB(int nowbit,int val)
{
    if(val==1)
    {
        if(BITB[nowbit]==1)
        {
            BITB[nowbit]=0;
            return;
        }
        else
        {
            BITB[nowbit]=1;
            delB(nowbit-1,val);
        }
    }
    else
    {
        if(BITB[nowbit]==0)
        {
            BITB[nowbit]=1;
            return;
        }
        else
        {
            BITB[nowbit]=0;
            delB(nowbit-1,val);
        }
    }
}

inline int power(int x,int y)
{
    int res=1;
    while(y)
    {
        if(y&1)res*=x;
        x*=x;
        y>>=1;
    }
    return res;
}

int dis[Maxn*2],bg,maxd;
inline void calcA()
{
    for(int i=2;i<=nowbitA;i++)
    {
        --bg;
        if(BITA[i]==0){if(BITB[i]==1)dis[bg]++;if(!maxd)maxd=bg;}
        else{if(BITB[i]==0)dis[bg]--;}
    }
}

inline void calcB()
{
    for(int i=2;i<=nowbitA;i++)
    {
        --bg;
        if(BITB[i]==0){if(BITA[i]==1)dis[bg]++;if(!maxd)maxd=bg,_=1;}
        else{if(BITA[i]==0)dis[bg]--;}
    }
}
inline bool Isl()
{
    for(int i=2;i<=nowbitA;i++)
    {
        if(BITA[i]==0&&BITB[i]==1)return true;
        if(BITA[i]==1&&BITB[i]==0)return false;
    }   
}

inline int calcdis()
{
    int t=0,bz=0;
    for(int i=bg;i<=maxd;i++)
    {
        if(dis[i])t+=dis[i]*power(2,(i-bg));
    }
    return t;
}

inline bool judgesame()
{
    if(nowbitA!=nowbitB)return false;
    for(int i=1;i<=nowbitA;i++)if(BITA[i]^BITB[i])return false;
    return true;
}

int main()
{
    BITA[nowbitA]=BITB[nowbitB]=1;
    scanf("%s",ch+1);
    int len=strlen(ch+1);
    for(int i=1;i<=len;i++)
    {
        if(ch[i]=='1')
        {
            nowbitA++;
            BITA[nowbitA]=0;
        }
        else if(ch[i]=='2')
        {
            nowbitA++;
            BITA[nowbitA]=1;
        }
        else if(ch[i]=='U'){nowbitA--;}
        else if(ch[i]=='L'){delA(nowbitA,1);}
        else delA(nowbitA,-1);
    }
    scanf("%s",ch+1);
    len=strlen(ch+1);
    for(int i=1;i<=len;i++)
    {
        if(ch[i]=='1')
        {
            nowbitB++;
            BITB[nowbitB]=0;
        }
        else if(ch[i]=='2')
        {
            nowbitB++;
            BITB[nowbitB]=1;
        }
        else if(ch[i]=='U'){nowbitB--;}
        else if(ch[i]=='L'){delB(nowbitB,1);}
        else delB(nowbitB,-1);
    }
    if(judgesame())cout<<0<<endl;
    else
    {
    int ans=0;
    if(nowbitA>nowbitB){ans+=(nowbitA-nowbitB);nowbitA=nowbitB;}
    else {ans+=(nowbitB-nowbitA);nowbitB=nowbitA;}
    bg=nowbitA;

    if(Isl())calcA();
    else calcB();
    while(1)
    {
        if(maxd-bg>=25)
        {
            bg++,nowbitA--,nowbitB--;ans+=2;
        }
        else
        {
            int t1=calcdis();
            bg++,nowbitA--,nowbitB--;
            int t2=calcdis();
            if(t1>=(t2+2))ans+=2;
            else
            {
                ans+=t1;
                break;
            }
        }
    }
    cout<<ans<<endl;
    }
}

这次代码长的吓人。。还用了线段树也是够拼。

成功的脱了一次非入了一次欧orz。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值