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 ", ++kcase, ans); } return 0; }
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 ", ++kcase, value()); } return 0; }
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 ", 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 ", res - ans); } return 0; }
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 ", ++kcase, ans); } return 0; }
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 ", q); else { q -= n; q %= 2*(n - 1); if (q == 0) printf("%lld ", n); else if (q < n) printf("%lld ", q); else printf("%lld ", q - n + 1); } } return 0; }
这次的题就补到这里吧,感觉智商已经欠费╮(╯﹏╰)╭╮(╯﹏╰)╭