2018ecjtu 双基

版权声明:个人笔记,仅供复习 https://blog.csdn.net/weixin_42373330/article/details/84195929

G题 (数位dp)

描述:

链接:https://ac.nowcoder.com/acm/contest/221/G
来源:牛客网

7的意志
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
定义一个序列a:7,77,777…,7777777(数字全为7的正整数,且长度可以无限大)
clearlove7需要从含有7的意志的数里获得力量,如果一个整数能被序列a中的任意一个数字整除,并且其数位之和为序列a中任意一个数字的倍数,那么这个数字就含有7的意志,现在给你一个范围[n,m],问这个范围里有多少个数字含有7的意志。

输入描述:
多组输入,每行两个个整数n,m(1<=n<=m<=1e18),如果输入为"0 0",停止程序。
输出描述:
每一行输出含有7的意志的数的个数。
示例1
输入
复制
1 7
1 100
1 1000
0 0
输出
复制
1
3
21
说明
1到100中符合条件的数字为7,70,77

参考链接:HDU2089 不要62【数位DP+记忆化搜索】


代码:

/* ecjtu 双基 */
/* 7的意志 */
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
#define ll long long
const int mod=1e9+7;
int digits[20];
ll dp[20][10][10];
/*变量
dp[pos][pre][sum] - pos位到0位 的数的和%7的余数为pre,数位和%7为sum的 个数
sum - 数位和的余数
pre - 数的余数 例如113,pre最先取1 -> pre=(pre*10+1)%7 -> pre=(pre*10+3)%7

//之前刚刚学了数位dp,比赛时结果这道题还是做不来,看来没有理解透数位dp,不过这道题可以让我更加熟悉


*/

ll dfs(int pos,int pre, int sum,bool limit)
{
    if(pos==-1) return (sum%7==0&&pre%7==0);
    if(!limit&&dp[pos][pre][sum]!=-1) return dp[pos][pre][sum];
    int up=limit?digits[pos]:9;
    ll ans=0;
    for(int i=0;i<=up;i++)
    {
        ans=ans+dfs(pos-1,(pre*10+i)%7,(sum+i)%7,limit&&i==digits[pos]);
    }
    if(!limit&&dp[pos][pre][sum]==-1)
        dp[pos][pre][sum]=ans;
    return ans;
}
ll solve(ll n)
{
    int len=0;
    memset(dp,-1,sizeof(dp));
    while(n)
    {
        digits[len++]=n%10;
        n/=10;
    }
    return dfs(len-1,0,0,true);
}
int main()
{
    ll n, m;
    while(scanf("%lld%lld",&n, &m)!=EOF)
    {
        if(n==0&&m==0) break;
        printf("%lld\n",solve(m)-solve(n-1));
    }
    return 0;
}

I题:

描述

链接:https://ac.nowcoder.com/acm/contest/221/I
来源:牛客网

数学题
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
题面描述
最近,华东交通大学ACM训练基地的老阿姨被一个数学问题困扰了很久,她希望你能够帮她解决这个问题。
这个数学问题是这样的,给你一个N,要求你计算

gcd(a,b)表示a和b的最大公约数
输入描述:
多组输入,每行一个整数n(1<=n<=10^14)。
输出描述:
每行一个整数,表示答案。由于答案会很大你要对1000000007取模。
示例1
输入
复制
4
10
输出
复制
6
35
说明
样例一,2+4=6。
样例二,2+4+5+6+8+10=35。

题意:
求1到n之间与n不互质的数的总和
问题分析:
这题可以换成用总和(即n*(n+1)/2)减去1到n之间与n互质的数的总和
1.求1到n之间与n互质的数的总和 ,就是n*phi(n)/2, phi(n)就是1到n之间与n互质的
个数,证明见下面的参考链接[1到n之间与n互质的数的总和]
2.由于最后结果是要取余的,故要将除以2转换成乘以2模mod(这题mod是e9+7),
然后在取余。有关逆元的用处见下面参考链接[逆元]

c++编程语言如下:
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const LL mod = 1000000007 ;
LL phi(LL x){
    LL ans = x;
    for(LL i = 2; i*i <= x; i++){
        if(x % i == 0){
            ans = ans / i * (i-1);
            while(x % i == 0) x /= i;
        }
    }
    if(x > 1) ans = ans / x * (x-1);
    return ans;
}
LL quick(LL x, LL n){
    LL res = 1LL ;
    while( n ){
        if(n&1)res=res*x%mod;
        x=x*x%mod;
        n>>=1;
    }
    return res;
}
int main(){
    LL n ;
    while( ~scanf("%lld",&n) ){
        //N*phi(N)/2
        LL res ;
        if( n == 1 ){
            cout << 0 << endl;
            continue ;
        }
        LL ans = (((n%mod)*((n+1)%mod))%mod)*quick(2,mod-2)%mod-(((n%mod)*(phi(n)%mod))%mod)*quick(2,mod-2)%mod;
        ans %= mod;
        printf("%lld\n",(ans+mod)%mod);
    }
    return 0 ;
}

K题:

描述:

链接:https://ac.nowcoder.com/acm/contest/221/K
来源:牛客网

MIKU酱的氪金宝典
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
MIKU酱是个玩游戏氪金的人,游戏公司给她制定了新的规则,如果想从关卡i到关卡j,你需要交一些钱就可以了,但同时,MIKU酱的爸爸zjw很爱她,所以她可以每过一关就向她爸要一次钱,但她爸每次给他的钱是固定的,MIKU酱是个不会节省的女孩,哪怕每次多出来的钱,她也会拿去买肥宅快乐水,所以每次要的钱一定花完,因为MIKU酱不想挨骂,所以希望每次他爸给她的钱最少。
tips(到达第n关即通过,每到达一关一定能通过这关)
输入描述:
多组输入,每个样例第一行输入两个整数n,m(2<=n<=200,1<=m<=1000)表示关卡和规则的数量,接下来m行规则,每行输入x,y,w(w<=1000),表示从关卡x到y需要缴纳w的费用,保证题目有解,不会出现x=y的情况
输出描述:
输出一行,代表最少的钱
示例1
输入
复制
4 4
1 2 2
1 3 1
2 4 3
3 4 1
输出
复制
1


代码:

/* ecjtu 双基 */
/* 7的意志 */
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
#define ll long long
#define INF 0x3f3f3f3f
ll e[225][225];
ll n,m;
void flyod()
{
    for(ll k=1;k<=n;k++)
        for(ll i=1;i<=n;i++)
            for(ll j=1;j<=n;j++)
            {
                ll t=max(e[i][k],e[k][j]);
                if(e[i][j]>t)
                    e[i][j]=t;
            }
    cout<<e[1][n]<<endl;
}

int main()
{
    int x,y, z;
    while(scanf("%lld%lld",&n,&m)!=EOF)
    {
        memset(e,INF,sizeof(e));
        while(m--)
        {
            scanf("%d%d%d",&x,&y,&z);
            if(z<e[x][y]) e[x][y]=z;

        }
        for(ll i=1;i<=n;i++)
            e[i][i]=0;
        flyod();
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_42373330/article/details/84195929