[20181101][模拟赛]

题面

T1

思路

裸地等比数列求和。然而考试的时候并不会。学会了一种很nb的等比数列求和的方法。

假如我们要求\(\sum\limits_{i = 1}^n{x^i}\),那么我们设\(P=\sum\limits_{i = 1}^n{x^i}\),容易发现,P的x进制表示就是1111....111,共m个1,然后我们考虑\(Q=x^{m+1}\)的x进制表示,就是1000....000,共m个0。然后将Q-1求出来。就是\(\overline{(x-1)(x-1)...(x-1)}_x\)然后求出\(\frac{Q-1}{x-1}\)就可以了,因为要取模,所以求个逆元就好了。

真正的等比数列求和公式

\[S_n=\frac{a_1*(1-q^n)}{(1-q)}(q为公比)\]

代码

#include<cstdio>
#include<iostream>
using namespace std;
typedef long long ll;
const int mod = 1e9+7;
ll read() {
    ll x = 0,f = 1;char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9') {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x * f;
}
ll qm(ll x,int y) {
    ll ans = 1;
    for(;y;y >>= 1,x = x * x % mod) 
        if(y & 1) ans = ans * x % mod;
    return ans;
}
int main() {
    freopen("sum.in","r",stdin);
    freopen("sum.out","w",stdout);
    int n = read(),m = read();
    ll ans = 0;
    ans = m;
    for(int i = 2;i <= n;++i) {
        ll k = (qm(i,m + 1) - 1 + mod) % mod;
        k *= qm(i - 1,mod - 2);
        k %= mod;
        k = (k - 1) % mod;
        ans = (ans + k) % mod;
    }
    cout<<ans;
    return 0;
}

T2

思路

其实并不难,仔细一想就可以发现其实就是将整棵树的边权之和乘以2,然后减去距离根结点最远的点与根节点的距离

代码

#include<cstdio>
#include<queue>
#include<iostream>
using namespace std;
typedef long long ll;
const int N = 50010;
ll read() {
    ll x = 0,f = 1;char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9') {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x * f;
}
struct node{
    int v,nxt,w;
}e[N * 2];
int dis[N],ejs,head[N];
void add(int u,int v,int w) {
    e[++ejs].v = v;e[ejs].w = w; e[ejs].nxt = head[u];head[u] = ejs;
}
int ans,Max = 0;
queue<int>q;
int vis[N];
void bfs() {
    while(!q.empty()) q.pop();
    dis[1] = 0;
    q.push(1);
    vis[1] = 1;
    while(!q.empty()) {
        int u = q.front();
        q.pop();
        for(int i = head[u];i;i = e[i].nxt) {
            int v = e[i].v;
            if(vis[v]) continue;
            dis[v] = dis[u] + e[i].w;
            Max = max(Max,dis[v]);
            q.push(v);
            vis[v] = 1;
        }
    }
}
int main() {
    freopen("tour.in","r",stdin);
    freopen("tour.out","w",stdout);
    int n = read();
    for(int i = 1;i < n;++i) {
        int u = read(),v = read(),w = read();
        add(u,v,w);
        add(v,u,w);
        ans += w * 2;
    }
    bfs();
    cout<<ans - Max;
    return 0;
}

T3

思路

发现其实只有数组中的幸运数字才是有贡献的。所以可以先把这些数字提取出来,然后dp。用f[i][j]表示前i种幸运数字中,选j种的方案数。最后统计一下答案。

代码

#include<cstdio>
#include<iostream>
#include<map>
#define int ll
using namespace std;
typedef long long ll;
const int N = 100000 + 100;
const int mod = 1e9 + 7;
map<int,int>ma;
ll read() {
    ll x = 0,f = 1;char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9') {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x * f;
}
ll jc[N],inv[N],tot,a[N],OK[N];
ll qm(ll x,int y) {
    ll ans = 1;
    for(;y;y >>= 1,x = x * x % mod)
        if(y & 1) ans = ans * x % mod;
    return ans;
}
ll C(ll x,ll y) {
    return (ll)jc[x] * (ll)inv[y] % mod * (ll)inv[x-y] % mod;
}
int pd(int x) {
    while(x) {
        if(x % 10 != 4 && x % 10 != 7) return 0;
        x/=10;
    }
    return 1;
}
int f[2100][2100];
signed main() {
    freopen("lucky.in","r",stdin);
    freopen("lucky.out","w",stdout);
    int n = read(),K = read();
    for(int i = 1;i <= n;++i) a[i] = read();
    jc[0] = 1;
    for(int i = 1;i <= n;++i) jc[i] = (ll)jc[i - 1] * (ll)i % mod;
    inv[n] = qm(jc[n],mod - 2);
    for(int i = n - 1;i >= 0; --i) inv[i] = (ll)inv[i + 1] * (i + 1) % mod;
    int cnt = 0;
    for(int i = 1;i <= n;++i) {
        if(pd(a[i])) {
            if(!ma[a[i]])
            OK[++tot] = a[i];
            ma[a[i]]++;
        }
        else cnt++;
    }
    f[0][0] = 1;
    for(int i = 1;i <= tot;++i) {
        f[i][0] = 1;
        for(int j = 1;j <= tot; ++j) {
            f[i][j] = (f[i-1][j] + f[i-1][j - 1] * ma[OK[i]] % mod) % mod;
        }
    }
    ll ans = 0;
    for(int i = 0;i <= tot;++i) {
        ans += (ll)f[tot][i] * C(cnt,K-i) % mod;
        ans >= mod ? ans -= mod : 0;
    }
    cout<<ans;
    return 0;
}

总结

预计得分50 + 100 +100 = 250

实际得分50 + 100 + 50 = 200

最后一个题想了一个假的容斥实力坑自己。还能跟暴力拍过去。。。。t1不会,还是有太多坑要填

一言

既然我找不到你,只好站在显眼的地方让你找到了。 ——何以笙箫默

转载于:https://www.cnblogs.com/wxyww/p/9890773.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值