码迷,mamicode.com
首页 > 其他好文 > 详细

JZOJ 1121. Fix

时间:2020-08-10 14:33:20      阅读:66      评论:0      收藏:0      [点我收藏+]

标签:name   break   struct   一个   double   printf   mes   pac   min   

1001 Road To The 3rd Building

题意

? 一串序列,求所有连续区间数字和的期望。

思路

? 先求出前缀和\(s[i] \ (\sum_{k=1}^{i} a[k])\),做如下操作

  • 长度为1的区间的和加起来得到 \(s[n]\)

  • 长度为2的区间的和加起来得到 \(s[n]+s[n-1]-s[1]\)

  • 长度为3的区间的和加起来得到 \(s[n]+s[n-1]+s[n-2]-s[1]-s[2]\)

? 规律就很明显了,再做一次前缀和的前缀和。

代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 2e5 + 7;
const int mod = 1e9 + 7;

ll T, n;
ll s[maxn];

ll qpow(ll a, ll b) {
    ll ans = 1;
    while(b) {
        if(b & 1) ans = ans * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ans;
}

ll m(ll a) {
    return (a % mod + mod ) % mod;
}

int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    freopen("data.in", "r", stdin);
    //freopen("data.out", "w", stdout);
    cin >> T;
    while(T--) {
        cin >> n;
        for(int i = 1; i <= n; i++) cin >> s[i];
        for(int i = 1; i <= n; i++) s[i] = (s[i] + s[i-1])%mod;
        for(int i = 1; i <= n; i++) s[i] = (s[i] + s[i-1])%mod;
        ll ans = 0, temp = 0;
        for(int i = 1; i <= n; i++) {
            ans += m(m(s[n]-s[n-i]-s[i-1]) * qpow(i, mod - 2) % mod);
            ans %= mod;
        }
        ans = ans * qpow(n*(n+1)/2%mod, mod -2) % mod;
        cout << m(ans) << endl;
    }
    return 0;
}

1002 Little Rabbit‘s Equation

题意

? 给一个四则运算公式,判断能满足这个公式的最小进制。

思路

? 直接模拟,需要注意除法不是整数除法,所以判断的时候使用\(b*c==a\)

代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1e5 + 7;
const int mod = 1e9 + 7;

string s;
map<char, int> mp;
void init() {
    mp[‘0‘] = 0; mp[‘1‘] = 1; mp[‘2‘] = 2; mp[‘3‘] = 3;
    mp[‘4‘] = 4; mp[‘5‘] = 5; mp[‘6‘] = 6; mp[‘7‘] = 7;
    mp[‘8‘] = 8; mp[‘9‘] = 9; mp[‘A‘] = 10; mp[‘B‘] = 11;
    mp[‘C‘] = 12; mp[‘D‘] = 13; mp[‘E‘] = 14; mp[‘F‘] = 15;
}

ll convert(int base, string num) {
    ll ans = 0, p = 1;
    for(int i = num.size() - 1; i >= 0; i--) {
        ans += mp[num[i]] * p;
        p = p * base;
    }
    return ans;
}

bool judge(int base, string a, char opt, string b, string c) {
    ll na = convert(base, a);
    ll nb = convert(base, b);
    ll nc = convert(base, c);
    if(opt == ‘+‘) return na + nb == nc;
    if(opt == ‘-‘) return na - nb == nc;
    if(opt == ‘*‘) return na * nb == nc;
    return nc * nb == na;
}

int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    freopen("data.in", "r", stdin);
    //freopen("data.out", "w", stdout);
    init();
    while(cin >> s) {
        string num[3];
        num[0] = num[1] = num[2] = "";
        int now = 0, ans = -1; char opt;
        for(int i = 0; i < s.size(); i++) {
            if(mp.count(s[i])) num[now] += s[i];
            else if(s[i] != ‘=‘) {
                opt = s[i];
                now++;
            }
            else now++;
        }
        int base = 2;
        for(int _ = 0; _ < 3; _++) {
            for(char ch: num[_]) {
                if(ch <= ‘9‘) base = max(base, ch - ‘0‘ + 1);
                else base = max(base, ch - ‘A‘ + 11);
            }
        }
        for(int i = base; i <= 16; i++) {
            if(judge(i, num[0], opt, num[1], num[2])) {
                ans = i;
                break;
            }
        }
        cout << ans << endl;
    }
    return 0;
}

1006 A Very Easy Graph Problem

题意

? 一个无向连通图,求所有的1点到0点的最短距离的路径和。

思路

? 考虑到第\(i\)条边的长度为\(2^i\),而\(\sum_{i=0}^{n-1}2^i \ = \ 2^n-1\)。所以需要尽量使用前面的边,按输入顺序求最小生成树即可。然后按照一个方向遍历最小生成树,记录每一个点顺着这个方向能到达的1类点和0类点。

? 最终答案就是按照遍历顺序求每条边的贡献

\[ans=\sum nxt[u][0]*(cnt1-nxt[u][1])*w + nxt[u][1]*(cnt0-nxt[u][0])*w; \]

代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1e5 + 7;
const int mod = 1e9 + 7;

int T, n, m, cnt[2], ans = 0;
int a[maxn], fa[maxn], nxt[maxn][2];
vector<pair<int, int>> G[maxn];
int find(int x) {
    return x == fa[x]?fa[x]:(fa[x] = find(fa[x]));
}
int qpow(int a, int b) {
    int ans = 1;
    while(b) {
        if(b & 1) ans = (ll)ans * a % mod;
        a = (ll)a * a % mod;
        b >>= 1;
    }
    return ans;
}
void dfs(int u, int from) {
    nxt[u][a[u]]++;
    for(auto p: G[u]) {
        if(p.first==from) continue;
        dfs(p.first, u);
        nxt[u][0] += nxt[p.first][0];
        nxt[u][1] += nxt[p.first][1];
    }
    // 遍历每一个点,与点直接相连的边的贡献为nxt[u][0]*(cnt1-nxt[u][1])*w + nxt[u][1]*(cnt0-nxt[u][0])*w;
    for(auto p: G[u]) {
        if(p.first == from) continue;
        ans = ((ll)ans + (ll)nxt[p.first][0] * (cnt[1] - nxt[p.first][1]) % mod * p.second) % mod;
        ans = ((ll)ans + (ll)nxt[p.first][1] * (cnt[0] - nxt[p.first][0]) % mod * p.second) % mod;
    }
}

int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    freopen("data.in", "r", stdin);
    //freopen("data.out", "w", stdout);
    cin >> T;
    while(T--) {
        cin >> n >> m;
        cnt[0] = cnt[1] = ans = 0;
        for(int i = 1; i <= n; i++) {
            cin >> a[i];
            cnt[a[i]]++;
            nxt[i][0] = nxt[i][1] = 0;
            fa[i] = i;
            G[i].clear();
        }
        // 最小生成树
        for(int i = 1; i <= m; i++) {
            int u, v, w;
            cin >> u >> v;
            w = qpow(2, i);
            int x = find(u), y = find(v);
            if(x == y) continue;
            fa[x] = y;
            G[u].push_back({v, w});
            G[v].push_back({u, w});
        }
        dfs(1, -1);
        cout << ans << endl;
    }
    return 0;
}

1009 Divisibility

题意

? 如下定义\(y=\overline{c_{1} c_{2} \cdots c_{n}}\)\(f(y)=\sum_{i=1}^{n} c_{i}, \text { if } \underbrace{f(f(\cdots f(y) \cdots))}_{\infty}\)

? 命题:对于b进制下任意一个数字是否都有 \(f(y)\)能被\(x\)整除,则\(y\)能被\(x\)整除,否者不能被\(x\)整除。

? 问命题是否成立

思路

? 考虑将一个数分解为\(num=a_nb^n+a_{n-1}b^{n-1}+...+a_2b^2+a_1b^1+a_0\)

? 要使各位数之和\(sum\%x == num\%x\),也就是\(b^n\%x=1,\quad b^{n-1}\%x=1, \quad..., \quad b^1\%x=1\),即\(b\%x=1\)

? 因此对于\(b\)进制下,当\(x=b-1\)时命题成立。

代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1e5 + 7;
const int mod = 1e9 + 7;

int T;
ll n, x;
int a[maxn];

int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    freopen("data.in", "r", stdin);
    //freopen("data.out", "w", stdout);
    cin >> T;
    while(T--) {
        cin >> n >> x;
        n--;
        if(n % x == 0) cout << "T\n";
        else cout << "F\n";
    }
    return 0;
}

JZOJ 1121. Fix

标签:name   break   struct   一个   double   printf   mes   pac   min   

原文地址:https://www.cnblogs.com/leiyuanze/p/13469526.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!