2016.09.03 YLOI 结题报告

来源:互联网 发布:mac创建win7安装u盘 编辑:程序博客网 时间:2024/06/06 00:20

快速荷叶叶变换

(fht.cpp/c/pas)

【问题描述】

荷叶叶是一位伟大的数♂学家。
荷叶叶发明了一个函数,并称之为快速荷叶叶变换(Fast H10 Transfrom)

FHT(N, M) = ∑i = 1..n∑j = 1..m (n mod i) * (m mod j)

但荷叶叶比较懒,对于函数的计算,荷叶叶把这个任务交给了你。
由于答案可能会很大,请输出答案对1000000007取模的值。

【输入格式】

一行,包含两个整数N,M。

【输出格式】

1个整数,FHT(N,M) mod 1000000007的值。

【输入输出样例】

fht.in fht.out 3 4 1

【数据规模与约定】

对于 40% 的数据,1 ≤ N,M ≤ 1000
对于 60% 的数据,1 ≤ N,M ≤ 10
6

对于 100% 的数据,1 ≤ N,M ≤ 10
9

从小到大枚举i发现

  • i = n … n/2 + 1 时, n mod i = 0, 1, 2, 3, 4, …;
  • i = n/2 … n/3 + 1时, n mod i= n mod (n/2), n mod (n/2) + 2, n mod (n/2) + 4, …
  • …(请读者自己试试)

剩下的最后一小段枚举即可。

  • 代码
#include <cstdio>#include <cstdlib>using namespace std;const long long mod = 1000000007;long long n, m;inline long long sum(long long s, long long tot, long long c){    return (s + s + (tot - 1) * c % mod) % mod * tot >> 1 % mod;}inline long long solve(long long n) //求出∑i = 1..n n % i {    register long long i = 2, l = 0, r = n + 1;    long long ans = 0;    do {      l = r - 1; r = n / i + 1;      (ans += sum(n % l, l - r + 1, i - 1)) %= mod;      i++;    }while(n / (i - 1) -  n / i> 1);    for(i = 1; i <= r - 1; i++)      (ans += n % i) %= mod;    return ans;}int main(){    freopen("fht.in", "r", stdin);    freopen("fht.out", "w", stdout);    long long sum;    scanf("%lld%lld", &n, &m);    sum = solve(n) * solve(m) % mod;    printf("%lld\n", sum);    return 0;}

幻象

(phantom.cpp/c/pas)

【问题描述】

phantom是一位爱思考的哲♂学家。
最近phantom得到了森の妖精的真传。在他练功的时候, 每秒他的思绪中
都有一定的概率浮现出奇♂异的幻象,持续x秒的幻象将产生x
2
的幻象值。
phantom练功发自真心,他想知道,在N秒内他期望产生的幻象值是多少。

【输入格式】

第一行包含 1 个正整数 N ,表示总时间 N 秒。
第二行包含 N 个用空格隔开的在[0,100]之间的正整数,其中第i个数a[i]
表示第i秒浮现幻象的概率为百分之a[i]。

【输出格式】

1 个实数,四舍五入后保留一位小数,表示期望幻象值。

【输入输出样例】

phantom.in phantom.out 3 1 50 50 50

【数据规模与约定】
对于 40%的数据 N ≤ 10
对于 60%的数据 N ≤ 100
对于 100%的数据,N ≤ 10 ^ 6
数据规模较大,请使用效率较高的读入方式。

设L[i]为第i秒幻象的持续时间的期望.
显然L[i] = (L[i-1] + 1) * a[i]%
设f[i]表示前i秒的答案
f[i] = f[i-1] + ((L[i-1] + 1) ^ 2 – L[i-1] ^ 2) * a[i]%
时间复杂度为O(N)

#include <cstdio>#include <cstdlib>using namespace std;const int maxn = 800005;double f[maxn], l[maxn], a[maxn];int n;inline double pow(double x){    return x * x;}int main(){    freopen("phantom.in", "r", stdin);    freopen("phantom.out", "w", stdout);    register int i, k;    scanf("%d", &n);    for(i = 1; i <= n; i++) {      scanf("%d", &k);      a[i] = k / 100.;      l[i] = (l[i - 1] + 1) * a[i];    }     for(i = 1; i <= n; i++)      f[i] = f[i - 1] + (pow(l[i - 1] + 1) - pow(l[i - 1])) * a[i];    printf("%.1lf", f[n]);    return 0;}

树上摩托

(sherco.cpp/c/pas)

【问题描述】

Sherco是一位经验丰富的魔♂法师。
Sherco在第零次圣杯战争中取得了胜利,并取得了王之宝藏——王の树。
他想把这棵树砍去任意条边,拆成若干棵新树,并装饰在他的摩托上,让他
的摩托更加酷炫。
但Sherco认为,这样生成的树不具有美感,于是Sherco想让每棵新树的节
点数相同。
他想知道有多少种方法分割这棵树。

【输入格式】

第一行一个正整数N,表示这棵树的结点总数。
接下来N-1行,每行两个数字X,Y表示编号为X的结点与编号为Y的结点
相连。结点编号的范围为[1,N]。

【输出格式】

一个整数,表示方案数。注意,不砍去任何一条边也算作一种方案。

【输入输出样例】

sherco.in sherco.out 6 3 1 2 2 3 2 4 4 5 5 6

【数据规模与约定】

对于40%的数据,N ≤ 15
对于60%的数据,N ≤ 10^5
对于100%的数据,N ≤ 10^6
数据规模非常大,请使用高效的读入方式。

暴力枚举删哪些边,期望得分40分。
观察到一些性质:
1.树的大小只可能是N的约数
2.树的大小确定的话,方案最多只有一种
我们可以枚举树的大小,并DFS判定是否可行。
时间复杂度O(n√n),期望得分60分。
继续观察到一些性质:
将原树看做一个有根树,一个节点可以作一个块的”根”,
当且仅当该节点的size能被块的大小整除
预处理出每个节点的size,枚举树的大小k,判断size为k的
倍数的节点数量是否为N/k。
时间复杂度O(NlnN)

#include <cstdio>#include <cstdlib>using namespace std;const int maxn = (int)1e6 + 5;struct edge {    int to, next;}e[maxn * 2];struct point {    int root, fa;};int n, ans, tot;int h[maxn], size[maxn], p[maxn];inline int read(){    char c;    do {      c = getchar();    }while(c < '0' || c > '9');    int sum = 0;    do {      (sum *= 10) += c - 48;      c = getchar();    }while('0' <= c && c <= '9');    return sum;}inline void add(int u, int v){    tot++;    e[tot] = (edge) {v, h[u]};    h[u] = tot;}void dfs(const point &s){    int i;    size[s.root] = 1;    for(i = h[s.root]; i; i = e[i].next)      if(e[i].to != s.fa) {        dfs((point){e[i].to, s.root});        size[s.root] += size[e[i].to];      }    p[size[s.root]]++;}int main(){    freopen("sherco.in", "r", stdin);    freopen("sherco.out", "w", stdout);    int i, j, u, v;    n = read();    for(i = 1; i < n; i++) {      u = read(); v = read();      add(u, v); add(v, u);    }    dfs((point){1, 0});    for(i = 1; i <= n; i++) {      int sum = p[i];      for(j = 2 * i; j <= n; j += i)        sum += p[j];      if(sum * i == n) ans++;    }    printf("%d\n", ans);    return 0;}
0 0
原创粉丝点击