Codeforces Round #232 (Div. 1)
这次运气比较好,做出两题。本来是冲着第3题可以cdq分治做的,却没想出来,明天再想好了。
A. On Number of Decompositions into Multipliers
题意:n个数a1,a2, a3...an求n个数相乘与a1*a2*a3*a4...an相等的排列个数。
分析:首先应该对ai分解质因数,求出所有ai中质因数及个数,枚举排列中每个数包含的质因数个数,例如质因数qi,有ni个,相应的排列中数包含质因数qi个数设为x1,x2,....xn, x1+x2+x3..+xn = ni , 那么对于qi共有C(ni+n-1, n-1)种情况。简单来说就是将ni分成n部分,这样想:有ni个球,需要分成n部分,也就是在n个球中插入n-1根木棍,这样分成n部分就相当于ni+n-1中选n-1个位置。最后把所有质因子可能的划分情况相乘起来就行了。
注意:分解质因数最后一个质因数可能很大!
代码:
#include <bits/stdc++.h>
#define in freopen("solve_in.txt", "r", stdin);
#define bug(x) printf("Line %d : >>>>>>>\n", (x));
#define pb push_back using namespace std;
typedef long long LL;
typedef map<int, int> Mps;
const int M = (int)1e9+;
const int maxn = ;
const int maxm = (int)1e5 + ;
LL inv[maxn];
int a[maxn];
Mps Div;
vector<int> dv; LL powmod(LL a, LL b) {
LL res = ;
while(b) {
if(b&)
res = (res*a)%M;
b >>= ;
a = (a*a)%M;
}
return res;
}
void getInv(int n) {
for(int i = ; i < n; i++) {
inv[i] = powmod(i, M-);
}
}
void getDiv(int x) {
int m = (int)sqrt(x+.);
for(int i = ; i <= m; i++) {
if(x%i == ) {
if(Div[i] == )
dv.pb(i);
while(x%i == ) {
Div[i]++;
x/=i;
}
}
}
if(x > ) {
if(Div[x] == )
dv.pb(x);
Div[x]++;
}
}
LL nCr(LL n, LL m) {
LL res = ;
for(int i = ; i < m; i++) {
res = res*(n-i)%M*inv[i+]%M;
if(res < )
res += M;
}
return (res + M)%M;
}
int main() { getInv(maxn);
int n;
scanf("%d", &n);
for(int i = ; i <= n; i++) {
scanf("%d", a+i);
getDiv(a[i]);
}
LL ans = ;
for(int i = ; i < (int)dv.size(); i++) {
int x = dv[i];
ans = ans*nCr(Div[x]+n-, n-)%M;
}
cout<<ans<<endl;
return ;
}
B. On Sum of Fractions
题意:给定n, u(i)表示不超过i的最大质数, v(i)表示大于i的最小质数。求对于所有的2<= i <= n , sum{1/(u(i)*v(i)}, 最简分式结果。
分析:
列出n的前几个数的1/u(i)*v(i),发现对于两个相邻素数pi, pi+1间的数i, 1/u(i)*v(i)结果是一样的。也就是说 对于 pi <= x < pi+1, sum{1/u(x)v(x)},化简后就是, 1/u(x)-1/v(x), 得到这个结论后,每次找到大于n的一个素数pi+1,结果就变成两部分, x < pi, 和 pi <= x < n, 第一部分化简就是1/2-1/pi ,第二部分:n-pi+1/(pi*pi+1), 两者之和合并一下就会得到一个表达式:2*(n+1)-2*(pi+pi+1)-pi*pi+1/(2*pi*pi+1)。求质数,用Miller-Rabin法判断前后两个质数就可以了。
代码:
#include <bits/stdc++.h>
#define in freopen("solve_in.txt", "r", stdin);
#define bug(x) printf("Line %d : >>>>>>>\n", (x));
#define pb push_back using namespace std;
typedef pair<int, int> PII;
typedef long long LL;
typedef map<int, int> Mps; LL powmod(LL a, LL b, LL c) {
LL res = ;
while(b) {
if(b&) res = res*a%c;
b >>= ;
a = (a*a)%c;
}
return res;
}
bool test(int n, int a, int d) {
if(n == )return true;
if(n == a) return true;
if((n&) == ) return false;
while(!(d&)) d >>= ;
int t = powmod(a, d, n);
while((d != n-) && (t != ) && (t != n-)) {
t = (LL)t*t%n;
d <<= ;
}
return (t == n-) || (d&) == ; }
bool isPrime(int n) {
if(n < ) return false;
int a[] = {, , };
for(int i = ; i <= ; i++) if(!test(n, a[i], n-)) return false;
return true;
}
pair<LL, LL> getPrime(LL n) {
LL x = n;
x++;
PII ans;
while() {
if(isPrime(x)) {
ans.first = x;
break;
}
x++;
}
x = n;
while() {
if(isPrime(x)) {
ans.second = x;
break;
}
x--;
}
return ans;
}
LL getGcd(LL a, LL b) {
return !b ? a : getGcd(b, a%b);
}
int main() { int T;
int n;
for(int t = scanf("%d", &T); t <= T; t++) {
scanf("%d", &n);
if(n == ) {
puts("1/6");
} else {
PII u = getPrime(n);
LL x = u.first, y = u.second;
LL a = *(n+)-*(x+y)+x*y;
LL b = *x*y;
LL c = getGcd(a, b);
printf("%I64d/%I64d\n", a/c, b/c);
}
}
return ;
}
C. On Changing Tree
题意:一棵n个结点的树,n <= 3*10^5, 给定q个操作。两种类型:
1 v x k ,给v及v子树上结点增加x-i*k,i表示子树上离v的距离
2 v,询问v结点上的值。
分析:
经过一上午的使劲YY,终于想到了CDQ分治的做法,其实比普通树状数组做法要慢,而且难写(也可能是我写得太挫了),复杂度最坏可能达到O(n*log^2n).1200ms能过也算是走运。
简要思路:首先将所有操作按照v结点的深度由大到小拍个序,具体分治的时候,对于原始编号在[l,r]的操作,要将它分成两部分,<= m 和>m 部分,然后考虑编号<=m,的修改操作(操作1) 对编号>m的询问操作(操作2)影响,其实也就是用操作1对所有影响的的要询问的结点的值更新。但是又不能针对每一<=m的操作1,去更新可能影响到的>m操作2, 这样复杂度会很高,那么问题关键就在于怎么按照深度的顺序将操作1作用累积起来,每次更新对结点v影响时,只需要考虑v到根节点的路径上最靠近v的一个操作1。
合并两个同一棵子树但是不同深度的操作1的影响时,例如1 v1 x1 k1, 1 v2 x2 k2, dep[v1] <= dep[v2],将v1合并到v2时,新的x = x1 - (dep[v2]-dep[v1])*k1 + x2, 新的k = k1+k2。同时在询问和更新某个结点v的上方且最靠近的v的操作1对应的结点时是利用线段树维护的,具体是将子树对应的叶节点一一编号,然后看做区间,将对应结点更新时,只需要将该节点的子树包含的叶子节点的区间进行更新,例如v对应叶子节点编号[L,R]只需要将一个标记cover设置为v,表示该段叶子结点对应的子树的根为最新的。这样做的依据是树中每棵子树包含的叶子结点都不同,但是可以连续编号的。
说的有点复杂,还是普通方法简单,这个也只是为了练习CDQ分治。||--
代码:
/*Time 2014 09 01 , 10:22 */
#include <bits/stdc++.h>
#define in freopen("solve_in.txt", "r", stdin);
#define bug(x) printf("Line %d : >>>>>>>\n", (x));
#define lson rt<<1, l, m
#define rson rt<<1|1, m+1, r
#define inf 0x0f0f0f0f
#define pb push_back using namespace std;
typedef long long LL;
const int maxn = *(int)1e5 + ;
const int M = (int)1e9 + ;
vector<int> g[maxn];
int ll[maxn], rr[maxn], dep[maxn], rk[maxn], t1[maxn], t2[maxn];
int cover[maxn<<];
int ans[maxn], x[maxn], k[maxn];
int qN;
int cnt, ct, vis[maxn]; struct Query
{
int type;
int v, x, k; } qu[maxn];
bool cmp(const int &a, const int &b)
{
return dep[qu[a].v] < dep[qu[b].v];
}
void dfs(int u)
{
if(g[u].size() == )
{
ll[u] = rr[u] = ++cnt;
return;
}
else ll[u] = inf, rr[u] = ;
for(int i = ; i < g[u].size(); i++)
{
int v = g[u][i];
dep[v] = dep[u]+;
dfs(v);
ll[u] = min(ll[u], ll[v]);
rr[u] = max(rr[u], rr[v]);
}
}
void pushDown(int rt)
{
if(cover[rt] != -)
{
cover[rt<<] = cover[rt<<|] = cover[rt];
cover[rt] = -;
}
}
void update(int rt, int l, int r, int L, int R, int u)
{
if(L <= l && R >= r)
{
cover[rt] = u;
return;
}
pushDown(rt);
int m = (l+r)>>;
if(L <= m)
update(lson, L, R, u);
if(R > m)
update(rson, L, R, u);
}
void query(int rt, int l, int r, int L, int R)
{
if(cover[rt] != -)
{
qN = cover[rt];
return;
}
pushDown(rt);
int m = (l+r)>>;
if(L <= m)
query(lson, L, R);
if(qN == - && R > m)
query(rson, L, R);
return;
}
void solve(int l, int r)
{
if(l >= r)
{
return;
}
int m = (l+r)>>;
t1[] = t2[] = ;
for(int i = l; i <= r; i++)
{
if(rk[i] <= m)
{
t1[++t1[]] = rk[i];
}
else
{
t2[++t2[]] = rk[i];
}
}
queue<int> q1, q2;
for(int i = l; i <= r; i++)
{
if(i <= m)
{
rk[i] = t1[i-l+];
if(qu[rk[i]].type == )
{
q1.push(rk[i]);
}
}
else
{
rk[i] = t2[i-m];
if(qu[rk[i]].type == )
q2.push(rk[i]);
}
}
cover[] = ;
ct++;
while(!q2.empty())
{
int xx = q2.front();
q2.pop();
int v1 = qu[xx].v;
while(!q1.empty() && dep[qu[q1.front()].v] <= dep[v1])
{
int yy = q1.front();
q1.pop();
int v2 = qu[yy].v;
int x2 = qu[yy].x;
int k2 = qu[yy].k;
qN = -;
query(, , cnt, ll[v2], rr[v2]);
x[v2] = (x2+x[qN])%M-(LL)(dep[v2]-dep[qN])%M*(LL)k[qN]%M;
if(x[v2] < ) x[v2] += M;
k[v2] = (k2+k[qN])%M;
update(, , cnt, ll[v2], rr[v2], v2);
}
qN = -;
query(, , cnt, ll[v1], rr[v1]);
ans[xx] = ((ans[xx]+x[qN])%M-(LL)(dep[v1]-dep[qN])%M*(LL)k[qN]%M+M)%M;
}
solve(l, m);
solve(m+, r);
}
int main()
{ int n, q;
scanf("%d", &n);
for(int i = ; i <= n-; i++)
{
int u = i+, v;
scanf("%d", &v);
g[v].pb(u);
}
dep[] = ;
dfs();
scanf("%d", &q);
for(int i = ; i <= q; i++)
{
rk[i] = i;
scanf("%d", &qu[i].type);
if(qu[i].type == )
{
scanf("%d%d%d", &qu[i].v, &qu[i].x, &qu[i].k);
}
else scanf("%d", &qu[i].v);
}
sort(rk+, rk+q+, cmp);
// for(int i = 1; i <= q; i++)
// cout<<qu[rk[i]].v<<endl;
solve(, q);
for(int i = ; i <= q; i++)
{
if(qu[i].type == )
{
printf("%d\n", ans[i]);
}
}
return ;
}
Codeforces Round #232 (Div. 1)的更多相关文章
- Codeforces Round #232 (Div. 2) B. On Corruption and Numbers
题目:http://codeforces.com/contest/397/problem/B 题意:给一个n ,求能不能在[l, r]的区间内的数字相加得到, 数字可多次重复.. 比赛的时候没有想出来 ...
- Codeforces Round #232 (Div. 1) A 解题报告
A. On Number of Decompositions into Multipliers 题目连接:http://codeforces.com/contest/396/problem/A 大意: ...
- Codeforces Round #232 (Div. 2) D. On Sum of Fractions
D. On Sum of Fractions Let's assume that v(n) is the largest prime number, that does not exceed n; u ...
- Codeforces Round #232 (Div. 2) On Sum of Fractions
Let's assume that v(n) is the largest prime number, that does not exceed n; u(n) is the smallest pri ...
- Codeforces Round #232 (Div. 2) C
C. On Number of Decompositions into Multipliers time limit per test 1 second memory limit per test 2 ...
- Codeforces Round #366 (Div. 2) ABC
Codeforces Round #366 (Div. 2) A I hate that I love that I hate it水题 #I hate that I love that I hate ...
- Codeforces Round #354 (Div. 2) ABCD
Codeforces Round #354 (Div. 2) Problems # Name A Nicholas and Permutation standard input/out ...
- Codeforces Round #368 (Div. 2)
直达–>Codeforces Round #368 (Div. 2) A Brain’s Photos 给你一个NxM的矩阵,一个字母代表一种颜色,如果有”C”,”M”,”Y”三种中任意一种就输 ...
- cf之路,1,Codeforces Round #345 (Div. 2)
cf之路,1,Codeforces Round #345 (Div. 2) ps:昨天第一次参加cf比赛,比赛之前为了熟悉下cf比赛题目的难度.所以做了round#345连试试水的深浅..... ...
随机推荐
- [转]Windows Shell 编程 第三章 【转自:http://blog.csdn.net/wangqiulin123456/article/details/7987901】
第三章 操作文件 我依然清楚地记得,Windows95 的贝塔版出现的情形,它在朋友之间和学院中传播,好酷,全新的文件管理器,一种全图标,全彩色可客户化的界面,以及活泼的动画标识使得在文件拷贝和删除方 ...
- EF架构~过滤导航属性等,拼接SQL字符串
拼接T-SQL串,并使它具有通用性 好处:与服务器建立一次连接,给服务器发一条SQL命令,即可实现 代码如下: 1 /// <summary> 2 /// 构建Insert语句串 3 // ...
- iOS开发,多个button数组,每个数组只能选中5项,多个数组只能选择3个。
由于常用xib,所以不想用代码写那么多个button.而且也懒的算位置 直接xib拉线成四个数组.水果,零食,饮料,甜点. 入题实现的功能就是,在这四个数组之中只能在3个数组只选中5项.有点绕(就比如 ...
- ZOJ 2625 Rearrange Them(DP)
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1625 题目大意:将n个数重新排列,使得每个数的前一个数都不能和之前的 ...
- CentOS 开启GD库
在php.ini 中没有找到"extension=php_gd2.dll"这行代码,这是因为CentOS一般没有预装GD库. 解决办法: 1.在线安装GD库 yum -y inst ...
- 【转】如何编译安装PHP扩展
本文参考 一开始安装PHP的时候,我们并不知道需要哪些扩展,所以只有等到我们真正用到的时候才想办法去安装. 安装PHP扩展最简单的办法就是 sudo apt-get install php5-xxx ...
- Redis和Memcache的区别分析 [转]
1. Redis中,并不是所有的数据都一直存储在内存中的,这是和Memcached相比一个最大的区别. 2. Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,hash等数据结构 ...
- Linux内核中的通用双向循环链表
开发中接触Linux越来越多,休息放松之余,免不了翻看翻看神秘的Linux的内核.看到双向链表时,觉得挺有意思的,此文记下. 作为众多基础数据结构中的一员,双向循环链表在各种“教科书”中的实现是相当的 ...
- iOS中数据库运用之前的准备-简单的数据库
1.数据持久化 数据持久化是通过文件将数据存储在硬盘上 iOS下主要有四种数据持久化方式 属性列表 对象归档 SQLite数据库 CoreData 数据持久化对的对比 1.属性列表.对象归档适合小数据 ...
- javascript之变量、作用域、作用域链
一.变量 javascript的变量是松散类型的,所谓松散类型就是说定义的变量可以用来保存任何类型的数据.定义变量时要使用var操作符后面跟变量名.这里的var是一个关键字,如果定义变量时省略了var ...