【第22期】观点:IT 行业加班,到底有没有价值?

NOIP模拟题 2016.8.27 [贪心] [DP] [计数问题]

原创 2016年08月28日 18:52:33

LGTB 与偶数
LGTB 有一个长度为N 的序列。当序列中存在相邻的两个数的和为偶数的话,LGTB 就能把它们删掉。
LGTB 想让序列尽量短,请问能将序列缩短到几个数?
输入
第一行包含一个数N 代表序列初始长度
接下来一行包含N 个数a1, a2, …, aN,代表序列
对于50% 的数据,1  N  1000
对于100% 的数据,1  N  105, 0  ai  109
输出
输出包含一个数代表操作后序列最短长度
样例
样例输入样例输出
10
1 3 3 4 2 4 1 3 7 1
2
2


LGTB 与序列
LGTB 有一个长度为N 的序列A,现在他想构造一个新的长度为N 的序列B,使得B 中的任意两个数都
互质。
并且他要使ai与bi对应项之差最小
请输出最小值
输入
第一行包含一个数N 代表序列初始长度
接下来一行包含N 个数A1, A2, …, AN,代表序列A
对于40% 的数据,1  N  10
对于100% 的数据,1  N  100, 1  ai  30
输出
输出包含一行,代表最小值
样例
样例输入样例输出
51
6 4 2 8
3
样例说明
样例中B 数组可以为1 5 3 1 8
3


LGTB 与大数
LGTB 有一个非常大的数,并且他想对它进行Q 次操作
每次操作是把这个大数中的某种数字全部替换成一个数字串
他想知道Q 次操作之后得到的数对1000000007(109 + 7) 取模的结果,请输出给他
输入
输入第一行代表一个串S 代表初始的数
接下来一行有一个数字Q 代表操作次数
接下来Q 行,每行一个形如a->b1b2b3…bk 的串,代表将a 变成b1b2b3…bk
对于40% 的数据,1  jSj  1000,1  Q  10
对于100% 的数据,1  jSj  105,1  Q  105,询问中b 串的总长度不超过105
注意b 串可以为空
输出
输出包含一个数字,代表LGTB 想要的结果
样例
样例输入样例输出
123123
1
2->00
10031003
样例输入样例输出
222
2
2->0
0->7
777
4


T1:
容易发现对于可合并项,不同的合并顺序不会对答案有影响,那么可以用栈来维护,边读边处理(考试的时候没有想到用栈。。就手写了个链表来维护)。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<climits>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
const int INF=0x3f3f3f3f;
const int maxn = 100005;
struct Node
{
    int pre,next;
    int val;
}node[maxn];
#define pre(i) node[i].pre
#define next(i) node[i].next
#define val(i) node[i].val
int n;
int a[maxn];
inline void init()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",a+i);
    for(int i=1;i<=n;i++)
    {
        val(i)=a[i]&1;
        pre(i)=i-1;
        next(i)=i+1<=n?i+1:0;
    }
    next(0)=1;
}
int work()
{
    int last=0,now=1;
    while(now)
    {
        if(!last) last=now,now=next(now);
        if(!now) break;
        if(val(last)==val(now))
        {
            last=pre(last);
            now=next(now);
            next(last)=now;
            pre(now)=last;
        }
        else last=now,now=next(now);
    }
    int ret=0;
    int root=next(0);
    while(root)
    {
        ret++;
        root=next(root);
    }
    return ret;
}
int main()
{
    freopen("even.in","r",stdin);
    freopen("even.out","w",stdout);
    init();
    int ans=work();
    printf("%d",ans);
    return 0;
}

T2:
容易想到状压dp,但是却不容易想到优化。。。
首先如果原数列中Ai>Aj,那么最优答案一定是Bi>Bj的情况。
这样的话,由于原数不大于30,那么B数列中的数一定不超过58,这样那么如果让前面的大数先用大的Bi去匹配,然后剩下的用1去填,一定可以得到最优解。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<climits>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
const int INF=0x3f3f3f3f;
const int maxn = 105;
const int maxp = 17;
const int prime[] = {0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53}; // 16 primes
int n,a[maxn];
int dp[maxp][1<<maxp];
int status[maxn];
void init()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",a+i);
    sort(a+1,a+n+1,greater<int>());
    memset(status,0,sizeof(status));
    for(int i=1;i<=58;i++)
        for(int j=1;j<=16;j++)
            if(i<prime[j]) break;
            else if(i%prime[j]==0) status[i]|=(1<<j-1);
}
int dynamic()
{
    memset(dp,0x3f,sizeof(dp));
    dp[0][0]=0;
    for(int i=1;i<=min(n,16);i++) // current to fill in
        for(int S=0;S<(1<<16);S++) // last status
            for(int num=1;num<=58;num++)
                if(!(status[num]&S))
                    smin(dp[i][S|status[num]],dp[i-1][S]+abs(a[i]-num));
    int ans=INF;
    for(int S=0;S<(1<<16);S++)
        smin(ans,dp[min(n,16)][S]);
    return ans;
}
int main()
{
    freopen("seq.in","r",stdin);
    freopen("seq.out","w",stdout);
    init();
    int ans=dynamic();
    if(n>16) for(int i=17;i<=n;i++) ans+=abs(a[i]-1);
    printf("%d",ans);
    return 0;
}

T3:
这题竟然用DP!!!!!!!完全没看出来。。
要抓住每一次修改对相同字符所做的操作,在以后的任何询问时都是一样的序列,这样就可以用dp来实现记忆化,从而达到省时的目的。
那么可以构成类似于一棵树的样子,然后从底向上计算。
考虑子树合并。。
每一条串从后往前进行处理,一边处理数值一边维护数字长度,方便下一次计算。
除此之外,数的长度也要取模!!这样就可以用费马小定理了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<climits>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
typedef long long LL;
const int maxn = 100005;
const int mod = 1000000007;
int quick_exp(int a,int p)
{
    if(!p) return 1;
    if(p==1) return a%mod;
    int tmp=quick_exp(a,p>>1);
    tmp=(LL)tmp*tmp%mod;
    if(p&1) return (LL)tmp*a%mod;
    else return tmp;
}
string s;
struct Query
{
    int val;
    string ss;
}que[maxn];
int q;
void init()
{
    cin>>s;
    scanf("%d",&q);
    for(int i=1;i<=q;i++)
    {
        char ch=getchar();
        while(!isdigit(ch)) ch=getchar();
        que[i].val=ch-'0';
        getchar();
        cin>>que[i].ss;
        que[i].ss.erase(0,1);
    }
}
#define maxbit 15
#define SIZE 9
int dp[maxn][maxbit],len[maxn][maxbit];
int dynamic()
{
    memset(len,0,sizeof(len));
    memset(dp,0,sizeof(dp));
    for(int i=0;i<=SIZE;i++) dp[q+1][i]=i,len[q+1][i]=1;
    for(int i=q;i>=1;i--)
        for(int j=0;j<=SIZE;j++)
            if(que[i].val^j)
            {
                dp[i][j]=dp[i+1][j];
                len[i][j]=len[i+1][j];
            }
            else
            {
                dp[i][j]=0; len[i][j]=0;
                int lens=que[i].ss.size();
                for(int p=lens-1;p>=0;p--)
                {
                    int to=que[i].ss[p]-'0';
                    dp[i][j]+=(LL)dp[i+1][to]*quick_exp(10,len[i][j])%mod;
                    if(dp[i][j]>=mod) dp[i][j]-=mod;
                    len[i][j]+=len[i+1][to]%(mod-1);
                    if(len[i][j]>=mod-1) len[i][j]-=mod-1; // Fermat Theory
                }
            }
    int lens=s.size();
    int d=0,l=0;
    for(int p=lens-1;p>=0;p--)
    {
        int to=s[p]-'0';
        d+=(LL)dp[1][to]*quick_exp(10,l)%mod;
        if(d>=mod) d-=mod;
        l+=len[1][to]%(mod-1);
        if(l>=mod-1) l-=mod-1;
    }
    return d;
}
int main()
{
    freopen("number.in","r",stdin);
    freopen("number.out","w",stdout);
    init();
    int ans = dynamic();
    printf("%d",ans);
    return 0;
}
版权声明:S'il vous plait. 举报

相关文章推荐

2016.8.29 LGTB解题报告

考试总结: 1.这道题还是花了不少的时间的,特别是对拍啊之类的,总是放不下,然后有一些实现的问题导致改错也改了很久;     解决方案:下一次在决定写程序的时候,一定要先在草稿纸上把实现算法的流程...

一次求两序列中位数分治算法探索历程

如今博主在上算法设计与分析这门课,前两天刚讲到了分治法。 下面照搬一下教材《算法设计与分析》(第2版,王红梅、胡明 编著)分治法的设计思想概述。 分治者,分而治之也。 分治法(divide an...

在一个长度为n(n < 1000)的整数序列中,判断是否存在某两个元素之和为k。

在一个长度为n(n 输入第一行输入序列的长度n和k,用空格分开。 第二行输入序列中的n个整数,用空格分开。输出如果存在某两个元素的和为k,则输出yes,否则输出no。样例输入 9 10 1...

【C语言】获取一个数二进制序列中所有的偶数位和奇数位,分别输出二进制序列

#include int main() { int arr[32]; int m=0,i=0,count=0; printf("请输入一个十进制数:\n"); scanf("%d",&m); for...

获取一个数二进制序列中所有的偶数位和奇数位,分别输出二进制序列。

#include #pragma warning(disable:4996) #include int main() { int date = 0; printf("请输入数字:"); sca...

【codeforces 727 C】【交互题 求原数组】【告诉你有一个长度为n序列,你可以问n个问题,每个问题为ai+aj等于多少,最后输出这个序列】

传送门:C. Guess the Array 描述: C. Guess the Array time limit per test 1 second ...

《剑指offer》——和为s的连续整数序列

题目:输入一个正整数s,打印出所有和为s的连续正数序列(至少含有两个数)。可以考虑用两个数small和big分别表示序列的最小值和最大值。首先把small初始化为1,big初始化为2。如果从small...

有两个序列a,b,大小都为n,序列元素的值是任意整数,无序。

要求:通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小。 例如: var a=[100,99,98,1,2, 3]; var b=[1, 2, 3, 4,5,40]。...

浙大PAT 2-13. 两个有序序列的中位数 (解题思路)

2-13. 两个有序序列的中位数 时间限制 40 ms 内存限制 32000 kB 代码长度限制 8000 B 判题程序 Stand...

noip2013 计数问题 (模拟)

P1848记数问题 Accepted 标签:NOIP普及组2013 描述 试计算在区间 1 到 n 的所有整数中,数字 x(0 ≤ x ≤ 9)共出现了多少次?例如,在...
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)