HDU2017多校联合 contest 1

1001.  Add More Zero

给出m,求解最小的k满足10^k <= 2^m。两边同时取以10为底的对数答案就出来了。

#include "bits/stdc++.h"
using namespace std;
int main(int argc, char const *argv[])
{
    int n; int kcase = 0;
    while (scanf("%d", &n) != EOF) {
        int ans = (int)n*log10(2.0);
        printf("Case #%d: %d\n", ++kcase, ans);
    }
    return 0;
}
View Code

 

1002. Balala Power!

题意:

给出n个字符串。每个字符代表一个0-25的值,各个字符的值要求不相同,而且对于长度大于1的字符串,第一个字符不能赋值为零。

思路:

直接模拟,从低位向高位进位,最后考虑下第一个字符时赋值是零的情况。

#include "bits/stdc++.h"
using namespace std;
typedef long long LL;
const int maxn = 100100;
const int mod = 1e9 + 7;
char s[maxn];
int da[maxn][30];
int ra[maxn];
int maxx;
bool head[maxn];
LL pow_mod(int n,int m){
    LL ans=1,base=n;
    while(m){
        if(m&1) ans = (ans*base)%mod;
        base = (base*base)%mod; m>>=1;
    }
    return ans;
}
int cmp(int x, int y) {
    for (int i = maxx; i >= 0; i--) {
        if (da[i][y] > da[i][x]) return -1;
        else if (da[i][y] < da[i][x]) return 1;
    }
    return 0;
}
LL value() {
    LL ans = 0;
    for (int i = 0; i < 26; i++) {
        for (int j = 0; j < maxx; j++) {
            ans = (ans + ra[i]*da[j][i]%mod*pow_mod(26, j)%mod)%mod;
        }
    }
    return ans;
}
void change(int x, int f) {
    for (int i = 0; i < 26; i++) {
        if (ra[i] == x) {
            swap(ra[i], ra[f]);
            if (head[i]) return change(x+1, i);
            return;
        }
    }
}
int main(int argc, char const *argv[])
{
    int n; int kcase = 0;
    while (scanf("%d", &n) != EOF) {
        memset(da, 0, sizeof(da));
        memset(head, false, sizeof(head));
        memset(ra, 0, sizeof(ra));
        maxx = 0;
        for (int i = 0; i < n; i++) {
            scanf("%s", s); int len =strlen(s);
            maxx = max(maxx, len);
            for (int j = len-1; j >= 0; j--) {
                int t = s[j] - 'a';
                if (j == 0 && len != 1) head[t] = true;
                da[len-1-j][t]++;
            }
        }
        for (int i = 0; i < 26; i++) {
            for (int j = 0; j < maxx; j++) {
                if (da[j][i] > 25 && j + 1 >= maxx) maxx++;
                int t = da[j][i];
                da[j + 1][i] += t/26, da[j][i]=t%26;
            }
        }
        for (int i = 0; i < 26; i++) {
            int k = 0;
            for (int j = 0; j < 26; j++) {
                int t = cmp(i, j);
                if (t == 0 && i < j) k++;
                else if (t == 1) k++;
            }
            ra[i] = k;
        }
        int z = 0;
        for (; z < 26; z++) if (ra[z] == 0) break;
        if (head[z]) change(1,z);
        printf("Case #%d: %lld\n", ++kcase, value());
    }
    return 0;
}
View Code

 

1003. Colorful Tree

题意:

有一棵树,每个节点都有一个颜色,定义任意两点之间的长度为两点之间的出现的不同颜色的数量。求出整棵树上的所有长度和。

思路:

我参考的是http://blog.csdn.net/Bahuia/article/details/76141574里的文章,博主写的很好,还有图可以参考。

按照我自己的理解,对于每棵树先假设每条路上都有所有的颜色,那么路的总长度就应该是n*(n-1)/2*tot。然后考虑反面,对于颜色color[i]来说在一个联通区域没有出现color[i],那么减掉多加的部分。将这个树按照颜色的联通区域进行分块,然后进行统计。

利用树形dp的思想,从树根开始dfs。当访问并且回溯到节点u的时候,根据节点u的颜色,判断子树上不含有颜色u并且和u联通的联通区域的大小(由u和他同颜色的子节点所包围的不含颜色u的最大联通区域)。从叶子节点向根推进,使得最后的联通区域集中在根节点。最后在对整棵树做统计。

 

#include "bits/stdc++.h"
using namespace std;
typedef long long LL;
const int maxn = 200010;
LL ans = 0;
bool vis[maxn];
std::vector<int> tree[maxn];
LL sum[maxn], sz[maxn], color[maxn];
int dfs(int u, int fa) {
    sz[u] = 1;
    LL allson = 0; // 表示u的子树上不含颜色u的联通块的个数
    for (int i = 0; i < tree[u].size(); i++) {
        int v = tree[u][i];
        if (v == fa) continue;
        int lastsum = sum[color[u]]; // 记录递归以前color[u]的个数
        sz[u] += dfs(v, u);
        LL add = sum[color[u]] - lastsum; //add记录的是以color[u]为根节点的最高子树的大小
        ans += (sz[v] - add)*(sz[v] - add - 1)/2;//不含color[u]的联通块的大小是sz[u]-add
        allson += sz[v] -add; //记录联通块的大小。
    }
    sum[color[u]] += allson + 1;//不含color[u]树的大小要增加。
    return sz[u];
}
int main(int argc, char const *argv[])
{
    int kcase = 0, n;
    while (scanf("%d", &n) != EOF) {
        ans = 0; int tot = 0;
        memset(sum, 0, sizeof(sum));
        memset(vis, false, sizeof(vis));
        for (int i = 1; i <= n; i++) {
            scanf("%lld", &color[i]);
            if (!vis[color[i]]) tot++;
            vis[color[i]] = true;
            tree[i].clear();
        }
        for (int i = 1; i < n; i++) {
            int a, b; scanf("%d%d", &a, &b);
            tree[a].push_back(b);
            tree[b].push_back(a);
        }
        printf("Case #%d: ", ++kcase);
        LL res = (LL)n*(LL)(n - 1)/2*(LL)tot; 
        if (tot == 1) { 
            printf("%lld\n", res);
            continue;
        }
        dfs(1, -1);
        for (int i = 1; i <= n; i++) {     
            if (!vis[i]) continue;
            ans += (n-sum[i])*(n-sum[i]-1LL)/2LL;
        }
        printf("%lld\n", res - ans);
    }
    return 0;
}
View Code

 

 

 1006.Function

题意:

对于集合a 有n个元素(0~n-1),对于集合b有m个元素(0~m-1),求出映射f的个数使得f(i)=bf(ai) 。

思路:

先观察映射f : f(i) = bf(ai),设xn表示xxn次下标(x-x映射),将ai进行n次映射之后变成了f(i) = bnf(ani)。若a的循环节为n,则此时bn应该等于b所以得到结论,要使得映射存在,必须a的循环节是b的整数倍。

将a和b分别表示为几个不相交的轮转的乘积,根据乘法计数原理进行统计。

#include "bits/stdc++.h"
using namespace std;
typedef long long LL;
const int maxn = 1e6 + 10;
const int MOD = 1e9 + 7;
int a[maxn], b[maxn];
bool vis[maxn];
std::vector<int> la;
std::vector<int> lb;
void get(int s[], vector<int> &res, int l) {
    memset(vis, false, sizeof(vis));
    for (int i = 0; i < l; i++) {
        if (vis[i]) continue;
        int t = s[i]; int len = 0;
        while (!vis[t]) {
            len++;
            vis[t] = true;
            t = s[t];
        }
        res.push_back(len);
    }
} 
int main(int argc, char const *argv[]) 
{
    int n, m;
    int kcase = 0;
    ios::sync_with_stdio(false);
    while (cin >> n >> m) {
        la.clear(); lb.clear();
        for (int i = 0; i < n; i++) cin >> a[i];
        for (int j = 0; j < m; j++) cin >> b[j];
        get(a, la, n); get(b, lb, m);
        int lena = la.size();
        int lenb = lb.size();
        LL ans = 1;
        for (int i = 0; i < lena; i++) {
            LL  res = 0;
            for (int j = 0; j < lenb; j++) {
                if (la[i]%lb[j] == 0) res = (res + lb[j])%MOD;  
            }
            ans = res*ans%MOD;
        }
        printf("Case #%d: %lld\n", ++kcase, ans);
    }
    return 0;
}
View Code

 

 

1011. KazaQ's Socks

题意:

一个人有n(LL)双袜子, 每次从柜子里取出编号最小的袜子穿上,晚上将袜子放到框里。当某天晚上有n-1双袜子要洗,那么当晚洗干净,第二天晚上将这n-1双袜子放到柜子里,问第q天他穿的是哪个编号的袜子。

多写几组样例就会发现规律,如有五双袜子:12345(12341235)。

#include "cstdio"
#include "cmath"
#include "cstring"
#include "algorithm"
using namespace std;
typedef long long LL;
int main(int argc, char const *argv[])
{
    LL n, q;
    int kcase = 0;
    while (scanf("%lld%lld", &n, &q) != EOF) {
        printf("Case #%d: ", ++kcase);
        if (n >= q) printf("%lld\n", q);
        else {
            q -= n; q %= 2*(n - 1);
            if (q == 0) printf("%lld\n", n);
            else if (q < n) printf("%lld\n", q);
            else printf("%lld\n", q - n + 1);
        }
    }
    return 0;
}
View Code

 

这次的题就补到这里吧,感觉智商已经欠费╮(╯﹏╰)╭╮(╯﹏╰)╭



​​

转载于:https://www.cnblogs.com/cniwoq/p/7241376.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值