2016 ICPC 北京

这套题总体来说效果不是很好,可能是题有些偏难(就是太菜了) 两道签到题都写了半天,而且写的还是乱七八糟的,明明思路清晰但还是写的乱七八糟的,当时心没有静下来 也反映出心态对代码能力的影响(也许代码能力本来就不强吧)



                E - What a Ridiculous Election


Given a string which consists of five digits('0'-'9'), like "02943", you should change "12345" into it by as few as possible operations. There are 3 kinds of operations:

1. Swap two adjacent digits.

2. Increase a digit by one. If the result exceed 9, change it to it modulo 10.

3. Double a digit. If the result exceed 9, change it to it modulo 10.

You can use operation 2 at most three times, and use operation 3 at most twice.

As a melon eater(Chinese English again, means bystander), which candidate do you support? Please help him solve the puzzle.

Input

There are no more than 100,000 test cases.

Each test case is a string which consists of 5 digits.

Output

For each case, print the minimum number of operations must be used to change "12345" into the given string. If there is no solution, print -1.

Sample Input

12435

99999

12374

Sample Output

1

-1

3


【题意】

给出 一个串 问 最少经过多少次变化  使12345 变成这个串;

给出变换方式

1 : 交换相邻两项,  无限制次数

2 :  某一位增加一    限制 3次  超过10  %10

3: 某一位 *2   限制2次    超过10  %10

【思路】

用一个三维数字 ans【num】【op2】【op3】  预处理 代表  数字为num的  操作2 操作3  用的次数  进行BFS 预处理

每次操作都保证ans【num】【op2】【op3】里的数最小 这是 bfs 结束的关键


E题总结:这个题当时看的时候也不是没有考虑到用搜索搜一下,但没有写,因为觉得情况可能比较复杂,就没有了写的欲望,平时练习的时候确实应该改一下这些坏毛病了,不然比赛的时候就算想出来了还是会漏掉许多细节吧。。。。虽然不一定能过吧,起码去尝试了,也比只是待在那里发急比较好


代码

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cmath>
#include <math.h>
#include <cstring>
#include <string>
#include <queue>
#include <stack>
#include <stdlib.h>
#include <list>
#include <map>
#include <set>
#include <bitset>
#include <vector>
#define mem(a,b) memset(a,b,sizeof(a))
#define findx(x) lower_bound(b+1,b+1+bn,x)-b
#define FIN      freopen("input.txt","r",stdin)
#define FOUT     freopen("output.txt", What a Ridiculous Election"w",stdout)
#define S1(n)    scanf("%d",&n)
#define SL1(n)   scanf("%I64d",&n)
#define S2(n,m)  scanf("%d%d",&n,&m)
#define SL2(n,m)  scanf("%I64d%I64d",&n,&m)
#define Pr(n)     printf("%d\n",n)
#define lson rt << 1, l, mid
#define rson rt << 1|1, mid + 1, r

using namespace std;
typedef long long ll;
const double PI=acos(-1);
const int INF=0x3f3f3f3f;
const double esp=1e-6;
const int maxn=1e5+5;

const int MOD=1000000007;
const int mod=1e9+7;
int dir[5][2]={0,1,0,-1,1,0,-1,0};

int ans[maxn][5][5];//次数

struct node
{
    int num[10];
    int op2,op3;
    int step;
};

int Q_sum(node A)
{
    int sum=0;
    for(int i=1;i<=5;i++)
    {
        sum+=A.num[i];
        sum*=10;
    }
    return sum/10;
}

void bfs(node t)
{
    queue<node> Q;
    mem(ans,INF);
    t.op2=3;//  +1
    t.op3=2;//  *2
    t.step=0;
    Q.push(t);
    int n=Q_sum(t);
    ans[n][t.op2][t.op3]=0;
    while(!Q.empty())
    {
        node u=Q.front();
        Q.pop();

        for(int i=2;i<=5;i++)//swap
        {
            node tu=u;
            swap(tu.num[i],tu.num[i-1]);
            int  num=Q_sum(tu);
            tu.step++;
            if(tu.step>=ans[num][tu.op2][tu.op3])
                continue;
            Q.push(tu);
            ans[num][tu.op2][tu.op3]=tu.step;
        }
        if(u.op2>0)//+1
        {
            for(int i=1;i<=5;i++)
            {
                node tu=u;
                tu.op2--;
                tu.num[i]=(tu.num[i]+1)%10;
                int num=Q_sum(tu);
                tu.step++;
                if(tu.step>=ans[num][tu.op2][tu.op3])
                    continue;
                Q.push(tu);
                ans[num][tu.op2][tu.op3]=tu.step;
            }
        }
        if(u.op3>0)//*2
        {
            for(int i=1;i<=5;i++)
            {
                node tu=u;
                tu.op3--;
                tu.num[i]=(tu.num[i]*2)%10;
                int num=Q_sum(tu);
                tu.step++;
                if(tu.step>=ans[num][tu.op2][tu.op3])
                    continue;
                Q.push(tu);
                ans[num][tu.op2][tu.op3]=tu.step;
            }
        }
    }
}

int main()
{
    node temp;
    for(int i=1;i<=5;i++)
        temp.num[i]=i;
    bfs(temp);
    char str[12];
    while(~scanf("%s",str+1))
    {
        node b;
        for(int i=1;i<=5;i++)
            b.num[i]=str[i]-'0';
        int n=Q_sum(b);
        int res=INF;
        for(int i=0;i<=3;i++)
            for(int j=0;j<=2;j++)
        {
            res=min(res,ans[n][i][j]);
        }

        if(res==INF)
            printf("-1\n");
        else
            printf("%d\n",res);
    }
    return 0;
}


                                                                   I - A Boring Problem

 

As a student ofthe school of electronics engineering and computer science in PekingUniversity, Kyle took the course named Advanced Algebra in his freshman year,which, unluckily, became his nightmare.

His teacher, Mr. X, has an approximately paranoid requirements inthe ability of calculation, from which his students suffer a lot.

One day,Mr. X got a whim that he wanted to know for a given integer k and a long numeric string S whose length is N, what is the result of ∑ij=1 F(j,i)for each i (1≤ i N), where

S[l] meansthe l-th digit in S, and l starts from 1.

Mr. X added theproblem to the midterm test. Please give a hand to Kyle and tell him the answermod1000000007.

Input

There aremultiple test cases.

The first lineof the input contains an integer T which means thenumber of test cases.

The first line of each test casecontains two integers, above mentioned N and k. The next line is the above mentioned string S. S consists of only digits(‘0’..‘9’).

Output

For each test case, print a single linerepresenting the result of for each i (1 ≤ i N)

Notes:

T ≤5

N ≤50,000, k ≤ 100

Sample Input

2

5 1

12345

5 1

54321

Sample Output

1 5 14 30 55

5 13 22 30 35


题意:

对于数字串 S ,S[l]S[l] 表示串 S 的第 l 个数字( l 从 1 开始标记)。

F(j, i)=(Σil=jS[l])F(j, i)=(Σl=jiS[l])

对于每个 i ,求 Σij=1F(j, i)


思路:

模拟暴力求每一项的结果:

第一项:(S1)k(S1)k

第二项:(S1+S2)k+(S2)k(S1+S2)k+(S2)k

第三项:(S1+S2+S3)k+(S2+S3)k+(S3)k(S1+S2+S3)k+(S2+S3)k+(S3)k

这样的复杂度将达到 O(N2×logK)O(N2×log⁡K) ,即使通过预处理出 45 万数(最大前缀和)的 K 次结果,复杂度仍将有 O(N2)O(N2)

考虑前缀和表示结果

第一项:(Pre1Pre0)k(Pre1−Pre0)k

第二项:(Pre2pre0)k+(Pre2Pre1)k(Pre2−pre0)k+(Pre2−Pre1)k

第三项:(Pre3Pre0)k+(Pre3Pre1)k+(Pre3Pre2)k(Pre3−Pre0)k+(Pre3−Pre1)k+(Pre3−Pre2)k

将其展开:

第一项:C0kPrek1+C1kPrek11(Pre0)1+...+CkkPre01(Pre0)kCk0Pre1k+Ck1Pre1k−1(−Pre0)1+...+CkkPre10(−Pre0)k

第二项:
C0kPrek2+C1kPrek12(Pre0Pre1)1+...+CkkPre02(Pre0Pre1)kCk0Pre2k+Ck1Pre2k−1(−Pre0−Pre1)1+...+CkkPre20(−Pre0−Pre1)k

第三项:C0kPrek3+C1kPrek13(Pre0Pre1Pre2)1+...+CkkPre03(Pre0Pre1Pre2)k


将 Pre0+Pre1+...+PrejPre0+Pre1+...+Prej 记作 PPrevjPPrevj ,预处理出所有的 PPrevjPPrevj 。

对每一项乘法求解的复杂度为 O(K)O(K) 。整体复杂度为 O(N×K)


I题总结:二项式定理在数论中的使用还是很多的,不管是之前的矩阵快速幂(2016 ICPC 沈阳)(https://blog.csdn.net/ac_blood/article/details/79719393),还是这个题都用到了二项式定理,二项式定理在简化操作方面还是用处很大的,以后遇见一些公式递推的题的时候,可以多往二项式定理方面想一下。。。


代码:

#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
int T, N, k;
long long pre[50010][110], pprev[50010][110], c[110][110];
char s[50010];
void init(){
    c[0][0]=1;
    for(int i=1;i<=100;++i){
        c[i][0]=c[i][i]=1;
        for(int j=1;j<i;++j)
            (c[i][j]=c[i-1][j-1]+c[i-1][j]) %= mod;
    }
}
int main()
{   
    init();
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d %d %s", &N, &k, s+1);
        for(int i=1;i<=N;i++)
        {
            pre[i][0] = 1;
            pre[i][1] = pre[i-1][1] + s[i]-'0';
            for(int m=2;m<=k;m++)
                pre[i][m] = (pre[i][m-1] * pre[i][1]) % mod;
        }
        for(int i=1;i<=N;i++)
        {
            for(int m=0;m<=k;m++)
                (pprev[i][m] = pprev[i-1][m] + (m%2?-1:1) * pre[i][m]) %= mod;
        }
        for(int i=1;i<=N;i++)
        {
            long long ans = 0;
            for(int m=0;m<=k;m++)
            {
                ans += c[k][m] * pre[i][k-m] % mod * pprev[i-1][m] % mod + mod;
                ans %= mod; 
            }
            printf("%lld%c", ans, i==N?'\n':' ');
        }
    }
}

                                                                        K - JiLi Number

 

Driver Ji likesthe digit “1”. He has an accumulator which shows the sum of input number. Helists all of positive number no more than N and startscounting from one, two, three ... Every time hecounts a number he will add the number of digit “1” in this number toaccumulator at the same time. The amazing thing happens! At some times, when hefinishes counting a number X, the number whichon the accumulator is X exactly, he willregard X as “JiLi Number” which means luckynumber. Now he wants to know the number of “JiLi Numbers” and the biggest “JiLiNumber” no more than N.

Input

There are several test cases and theeach test case is a line contains an positive integer N, (1 < N

10100)

Output

For each testcase, output two integers which donates the number of “JiLi Numbers” and thebiggest “JiLi Number”.

Sample Input

1

100000000000

Sample Output

11

831111111110


题意:

记 JiLi Number 指满足 前 K 个数([1, K] )中数字 1 的个数等于 K 的数 K 。

HINT:此处所指  和 数字 概念不同,例:数 11221 包含 3 个数字 1 和 2 个数字 2 。

求前 N 个数中有多少个 JiLi Number

思路:

考虑 :

  • [0, 9] 中有数字 1 个数 10×110=110×110=1
  • [0, 99] 中有数字 1 个数 100×210=20100×210=20
  • [0, 999999999] 中有数字 1 个数 109×910=9×108109×910=9×108
  • [0, 9999999999] 中有数字 1 个数 1010×1010=10101010×1010=1010
  • 之后可以考虑数字 1 的增长速度绝对大于数的增长速度,即后续不可能存在 JiLi Number 。

暴力预处理出 前 10101010 个数中的 JiLi Number (其实到 1111111110 即不存在后续,样例很良心)。


I题总结:

首先写的时候没看懂题意(很怕这种情况,一旦看不懂题意,然后看看别人过了一大堆,然后就会很急,冷静不了读题.....恶性循环) 后来补题的时候 ,觉得这个题也没有那么难,然后对着题解直接写......以后的时候还是应该自己先多想想,不然一些难题真的不会写....


#include<bits/stdc++.h>
#define ll long long

using namespace std;

ll n;
long long a[100] = {1,
199981,
199982,
199983,
199984,
199985,
199986,
199987,
199988,
199989,
199990,
200000,
200001,
1599981,
1599982,
1599983,
1599984,
1599985,
1599986,
1599987,
1599988,
1599989,
1599990,
2600000,
2600001,
13199998,
35000000,
35000001,
35199981,
35199982,
35199983,
35199984,
35199985,
35199986,
35199987,
35199988,
35199989,
35199990,
35200000,
35200001,
117463825,
500000000,
500000001,
500199981,
500199982,
500199983,
500199984,
500199985,
500199986,
500199987,
500199988,
500199989,
500199990,
500200000,
500200001,
501599981,
501599982,
501599983,
501599984,
501599985,
501599986,
501599987,
501599988,
501599989,
501599990,
502600000,
502600001,
513199998,
535000000,
535000001,
535199981,
535199982,
535199983,
535199984,
535199985,
535199986,
535199987,
535199988,
535199989,
535199990,
535200000,
535200001,
1111111110};

string str;

int main()
{

    while(cin>>str )
    {
        if(str.size() > 11)
        {
            cout<<"83 1111111110"<<endl;
        }
        else
        {
            n = 0;
        for(int i = 0; i < str.size(); i++)
        {
            n *= 10;
            n += str[i]-'0';
        }
        for(int i = 82; i >= 0; i--)
        {
            if(n >= a[i])
            {
                cout<<i+1<<" "<<a[i]<<endl;
                break;
            }
        }
        }

    }

    return 0;
}



整体总结:单题的总结上面已经有了,整体来说这套题的难度属于正常的水平,或许偏难一点,但是也不超过很多,有些题还是经验不足,做的题还是少了,而且最近写的题也少了,静不下心去写题,这个是最伤的....希望能尽快调整好状态吧





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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值