2019 2.15模拟赛

2019  2.15模拟赛

分裂

【问题描述】

你有一个大小为?的?????,每次你可以从你已有的?????中选择一 个大小不为1的?????,设他的大小为?,然后把它分裂成?和? − ?,其 中1 ≤ ? < ?,这样你获得的收益是? * (? − ?) 给定?,?,求最少分裂几次才能得到至少?的收益

 

 

【输入格式】

从文件 split.in 中读入数据。 第一行两个正整数?,?

【输出格式】

输出到文件 split.out 中。 输出一个非负整数表示答案 如果无法达到?的收益输出−1

 

【样例输入】

765 271828

【样例输出】

14

 

【数据规模】

对于30%的数据,有? ≤ 10

对于100%的数据,有2 ≤ ? ≤ 1000,1 ≤ ? ≤ 109

 

sol:首先对于30%的数据,各种乱搞都可以做。但我写了个dp,dp[i][j]表示大小为 i 的Jabby,切 j 刀可得的最大权值,事实可以过到200,但没有这档分。标算是这么想的:因为要把一个物体切成 j 个,肯定是尽量平均的最优,就枚举 j,然后模拟切得过程,n2水过,其实是可以n*logn的,j显然是可以二分的

inline void Solve_30pts()
{
    int i,j,k,l;
    dp[1][0]=0;
    for(i=2;i<=S;i++)
    {
        dp[i][0]=0;
        for(j=1;j<=i/2;j++)
        {
            for(k=0;k<=j;k++)
            {
                for(l=0;l<=i-j;l++) dp[i][k+l+1]=max(dp[i][k+l+1],dp[j][k]+dp[i-j][l]+j*(i-j));
            }
        }
    }
    for(i=0;i<=S;i++)
    {
        if(dp[S][i]>=M)
        {
            Wl(i);
            return;
        }
    }
}
dp代码
#include <bits/stdc++.h>
using namespace std;
typedef int ll;
inline ll read()
{
    ll s=0;
    bool f=0;
    char ch=' ';
    while(!isdigit(ch))
    {
        f|=(ch=='-'); ch=getchar();
    }
    while(isdigit(ch))
    {
        s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
    }
    return (f)?(-s):(s);
}
#define R(x) x=read()
inline void write(ll x)
{
    if(x<0)
    {
        putchar('-'); x=-x;
    }
    if(x<10)
    {
        putchar(x+'0'); return;
    }
    write(x/10);
    putchar((x%10)+'0');
    return;
}
#define W(x) write(x),putchar(' ')
#define Wl(x) write(x),putchar('\n')
int S,M;
int main()
{
    freopen("split.in","r",stdin);
    freopen("split.out","w",stdout);
    int i,j;
    R(S); R(M);
    for(i=2;i<=S;i++)
    {
        int tmp=S/i,opt=S%i;
        int Now=0,Sum=S;
        for(j=1;j<=i;j++)
        {
            int oo=tmp+((opt>=j)?1:0);
            Now+=oo*(Sum-=oo);
        }
        if(Now>=M)
        {
            Wl(i-1); return 0;
        }
    }
    puts("-1");
    return 0;
}
AC代码

 

异或计数

【问题描述】

给定长度为?的非负整数序列?,问有多少个长度为?的非负整数序列?, 满足: ?? ≤ ?? ?1 ??? ?2 ???...??? ?? = ?1 ??? ?2 ???...??? ?? 答案对1000000009取模

 

输入格式】

从文件 xor.in 中读入数据。 第一行一个正整数? 第二行?个非负整数??

【输出格式】

输出到文件 xor.out 中。 输出一个数字,表示答案

 

【样例输入】

4

1 2 3 4 

【样例输出】

6

 

【数据规模】

对于30%的数据,1 ≤ ? ≤ 10,?? ≤ 103

对于50%的数据,1 ≤ ? ≤ 20

对于70%的数据,1 ≤ ? ≤ 40

对于100%的数据,1 ≤ ? ≤ 105,?? ≤ 2 30

 

sol:完全参照题解做法,连中间两档部分分也不会。。。

dp[i][j][0,1]表示前i个数字,当前这位的异或和是j,是否有至少一位小于上限

考虑转移

枚举当前位Bit

{

  枚举0~n-1

  如果ai+1 Bit位是1         dp[i][j][k]*(a[i+1] and (2Bit-1-1)+1) ----> dp[i+1][j^1][k]   //使得取满

             dp[i][j][k]*2Bit-1--->dp[i+1][j][k|1]         //使得小于上限

  如果ai+1 Bit位是0        dp[i][j][k]*(a[i+1] and (2Bit-1-1)+1) -----> dp[i+1][j][k] //取满

}

统计的时候加上dp[n][(Sum>>Bit)&1][1] / 2Bit-1(至少有一位小于上限,统计完后ans+一种ai=bi的情况)

但我想不明白为什么要除以2Bit-1     。。。。。。。。。。。

updata:想明白了跑回来填坑:因为统计的是当前这位的贡献,并且为了方便,加答案时加上的是至少一位小于上限的,所以对于一个小于上限的数,其0~Bit-1位可以乱填,就能保证0~Bit-1位异或和的正确性了,所以其实满足正确性的只有一种,因此要除以2Bit-1  

Ps:处理的时候有个小优化,因为and 2Bit-1-1 这东西很烦,所以直接倒着枚举Bit,每次如果ai 在Bit位是1,就ai-2Bit

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll read()
{
    ll s=0;
    bool f=0;
    char ch=' ';
    while(!isdigit(ch))
    {
        f|=(ch=='-'); ch=getchar();
    }
    while(isdigit(ch))
    {
        s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
    }
    return (f)?(-s):(s);
}
#define R(x) x=read()
inline void write(ll x)
{
    if(x<0)
    {
        putchar('-'); x=-x;
    }
    if(x<10)
    {
        putchar(x+'0'); return;
    }
    write(x/10);
    putchar((x%10)+'0');
    return;
}
#define W(x) write(x),putchar(' ')
#define Wl(x) write(x),putchar('\n')
const int N=100005;
const ll Mod=1000000009;
int n,a[N];
ll Bin[35],dp[N][2][2];//dp[i][j][0,1]表示前i个数字,当前这位的异或和是j,是否有至少一位小于上限
inline void Ad(ll &x,ll y)
{
    x+=y;
    x-=(x>=Mod)?Mod:0;
    return;
}
inline ll Ksm(ll x,ll y,ll Mod)
{
    ll ans=1;
    while(y)
    {
        if(y&1) ans=ans*x%Mod;
        x=x*x%Mod;
        y>>=1;
    }
    return ans;
}
int main()
{
    freopen("xor.in","r",stdin);
    freopen("xor.out","w",stdout);
    int Bit,i;
    ll ans=0,Sum=0;
    R(n);
    for(i=1;i<=n;i++) {R(a[i]); Sum^=a[i];}
    for(Bit=29;Bit>=0;Bit--)
    {
        int o1,o2,oo=0;
        memset(dp,0,sizeof dp); dp[0][0][0]=1;
        for(i=1;i<=n;i++)
        {
            if(a[i]&(1<<Bit))
            {
                oo^=1;
                a[i]-=(1<<Bit);
                for(o1=0;o1<=1;o1++)
                {
                    for(o2=0;o2<=1;o2++)
                    {
                        Ad(dp[i][o1^1][o2],dp[i-1][o1][o2]*(a[i]+1)%Mod);
                        Ad(dp[i][o1][o1|1],dp[i-1][o1][o2]*(1<<Bit)%Mod);
                    }
                }
            }
            else
            {
                for(o1=0;o1<=1;o1++)
                {
                    for(o2=0;o2<=1;o2++)
                    {
                        Ad(dp[i][o1][o2],dp[i-1][o1][o2]*(a[i]+1)%Mod);
                    }
                }
            }
        }
        Ad(ans,dp[n][oo][1]*Ksm((1<<Bit),Mod-2,Mod)%Mod);
    }
    Wl((ans+1)%Mod);
    return 0;
}
/*
input
4
1 2 3 4
output
6
*/
View Code

 

 

brainfuck

【问题描述】

?????????是一种很有趣的语言,该题只考虑他的简化版。

这个语言的程序是一段字符串,一开始命令指针指在位置1,每次执行 后往后跳1格 一开始你有一个变量?,

这个语言有4种指令:

(1)+ : ? + +

(2)− : ? − −

(3)[:若?等于0,则命令指针跳到这个括号匹配的]

(4)] :若?不等于0,则命令指针跳到这个括号匹配的[

通俗的理解的话就是: [− − −− > ?ℎ???(?){ ] − − − − >}

一段程序是合法的当且仅当:括号都是匹配的,且程序不死循环

现在白鸟阳想知道长度为?的合法程序有多少个,答案对?取模

 

 

【输入格式】

从文件 brainfuck.in 中读入数据。 第一行两个正整数?,?

【输出格式】

输出到文件 brainfuck.out 中。 第一行一个整数,表示答案

 

【样例输入】

2 1000000000

【样例输出】

5

 

【数据规模】

对于30%的数据,1 ≤ ? ≤ 10

对于50%的数据,1 ≤ ? ≤ 50

对于100%的数据,1 ≤ ? ≤ 100,1 ≤ ? ≤ 109

 

sol:30分看上去很好写 410次,开个栈模拟,但我没打,考场上写了一个不能套括号的dp,到死都没发现自己看错题了

标算好像不难理解,但我抄了zyy的,所以就按另一种方法(其实很像的)

转移都在代码注释了(其实是我还有些小地方不是很理解)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll read()
{
    ll s=0;
    bool f=0;
    char ch=' ';
    while(!isdigit(ch))
    {
        f|=(ch=='-');
        ch=getchar();
    }
    while(isdigit(ch))
    {
        s=(s<<3)+(s<<1)+(ch^48);
        ch=getchar();
    }
    return (f)?(-s):(s);
}
#define R(x) x=read()
inline void write(ll x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x<10)
    {
        putchar(x+'0');
        return;
    }
    write(x/10);
    putchar((x%10)+'0');
    return;
}
inline void writeln(ll x)
{
    write(x);
    putchar('\n');
    return;
}
#define W(x) write(x),putchar(' ')
#define Wl(x) writeln(x)
const int N=105;
int n;
ll Mod;
ll g[N][N<<1],f[N][N<<1],dp_Pre[N][N<<1];
ll Perfect[N];
ll dp[N][N][N<<1]; //dp[i][j][k]表示长度为i,除当前位外(k!=0)的个数,当前变量x的值为k的方案数 
inline void Ad(ll &x,ll y)
{
    x+=y;
    x-=(x>=Mod)?Mod:0;
    return;
}
int main()
{
    freopen("brainfuck.in","r",stdin);
    freopen("brainfuck.out","w",stdout);
    int i,j,k,l;
    R(n); R(Mod);
    f[0][n]=1;
    for(i=0;i<=n-1;i++)
    {
        for(j=-i;j<=i;j++)
        {
            Ad(f[i+1][j+n+1],f[i][j+n]);
            Ad(f[i+1][j+n-1],f[i][j+n]);
        }
    }
    //f[Len][delta] 把x放进去变成x+delta
    for(l=1;l<=n-2;l++)
    {
        for(i=1;i<=n;i++)
        {
            for(j=1;j<i;j++) if(i%j==0)
            {
                Ad(dp_Pre[l][i+n],f[l][j+n]);
                Ad(dp_Pre[l][(-i)+n],f[l][(-j)+n]);
            }
        }
    }
    //dp_Pre[Len][delta] 把x放进去变成x+delta
    g[0][0]=1;
    for(i=1;i<=n;i++)
    {
        for(j=0;j<=i;j++)
        {
            Ad(g[i][j],(g[i-1][j]<<1));
            Ad(g[i][j],g[i-1][j+1]);
            if(j) Ad(g[i][j],g[i-1][j-1]);
        }
    }
    //g[Len][i] 长度为Len,未匹配括号为i的序列
    dp[0][0][n]=1;
    for(i=0;i<=n-1;i++)
    {
        for(j=0;j<=i;j++)
        {
            for(k=-i;k<=i;k++)
            {
                if(!dp[i][j][k+n]) continue;
                if(!k)
                {
                    for(l=1;l<=j;l++)
                    {
                        Ad(dp[i+2][l][k+n],dp[i][j][k+n]); //Last: ..... Now: ..[...] 这样加括号 
                    }
                    for(l=0;l<=n-i-2;l++)
                    {
                        Ad(dp[i+l+2][j][k+n],dp[i][j][k+n]*g[l][0]%Mod); //Last: ..... Now: .....[...(任意序列)]这样加括号
                    }
                }
                else
                {
                    for(l=1;l<=n-i-2;l++)
                    {
                        Ad(dp[i+l+2][j+1][n],dp[i][j][k+n]*dp_Pre[l][(-k)+n]%Mod); // Last ..... Now: .....[..(特定条件)]
                    }
                }
                Ad(dp[i+1][j+(k!=0)][k+n+1],dp[i][j][k+n]);  //Last:.....  Now:.....+
                Ad(dp[i+1][j+(k!=0)][k+n-1],dp[i][j][k+n]);  //Last:.....  Now:.....-
            }
        }
    }
    ll ans=0;
    for(i=0;i<=n;i++) for(j=-n;j<=n;j++)
    {
        Ad(ans,dp[n][i][j+n]);
    }
    Wl(ans);
    return 0;
}
/*
    4的34种情况 
    #define oo (+,-)
    oo,oo,oo,oo 16
    []oo,oo     4
    [oo]oo      4
    [oo,oo]     4
    +[-]        1
    -[+]        1
    +-[]        1
    -+[]        1
    [][]        1
    [[]]        1
    -------------------34
*/
/*
input
5 1000000007
output
92
*/
View Code

转载于:https://www.cnblogs.com/gaojunonly1/p/10392961.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值