Codeforces Beta Round #80 (Div. 2 Only)
2011-08-08 22:58
344 查看
A题,易水之
B题,易水之
C题
题意:判断给定图是否存在一个环,且不在环上点是否是以环上点引出的一个或多个生成树方法:先判图的连通性,然后去叶子节点(度为1),之后判断剩余点是否构成环(每个点度为2),且构成环点的个数不少于3
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int maxN = 100 + 2; #define f(i,s,e) for(int i = s; i <= e; ++i) #define i(x,y) scanf("%d %d", &x, &y) #define e(x,y,v) edge[x][y] = v, edge[y][x] = v #define a(x,y,v) Deg[x] += v, Deg[y] += v #define n() puts("NO") #define _n() puts("FHTAGN!") #define eq(x,y) if(x != y) return 0 static int N, M, u, v; static bool edge[maxN][maxN]; static int Deg[maxN]; static bool vst[maxN]; int _O_(int u) { vst[u] = 1; int ret = 1; f(j,1,N) if(edge[u][j] && !vst[j]) ret += _O_(j); return ret; } bool _O_O_() { f(k,1,N) f(i,1,N) if(Deg[i] == 1) f(j,1,N) if(edge[i][j]) e(i,j,0), e(j,i,0), a(i,j,-1), vst[i] = 0; return 1; } bool _O_O_O_() { int ret = 0; f(i,1,N) if(vst[i]) eq(Deg[i],2); else ++ret; return ret >= 3; } int main() { //freopen("data.in", "r", stdin); //freopen("data.out", "w", stdout); while( i(N, M) == 2 ) { f(i,1,N) f(j,1,N) e(i,j,0); f(i,1,N) Deg[i] = 0, vst[i] = 0; f(i,1,M) i(u,v), e(u,v,1), a(u,v,1); if( _O_(1) != N ) n(); else if( _O_O_() && _O_O_O_() ) _n(); else n(); } return 0; }
D题:未解
E题
题意:给定长度为N的序列 { A(1), A(2), ..., A(N)},有Q个查询,每个查询给2个数值 X 和 Y, 计算 Sum { A(X + K * Y) | X + K * Y <= N },N和Q的范围是 300,000思想:按照 Y 值从小到大排序,然后去计算每一个查询,当当前查询的Y值和前一个Y值相同,可以O(1)计算出来,否则枚举求解;注意,看起来好像是最暴利的方法,这里有一个处理,那就是对200个需要做单独处理,前200个处理中,如果出现 相邻 Y 值相等,算作一个,以下给出具体的分析
我们假设 N 取最大值即300,000,Q 也取得最大值300,000,这样,粗略的看,一次查询如果是最笨的穷举,那么最坏会是X = 1,Y=1,这样需要计算一次复杂度是多少呢?
答:是 K = (N - X ) / Y = (300,000 - 1) / 1 = 299,999 === 300,000
这样看起来好像总的复杂度是 Q*K=300,000 * 300,000 = 90,000,000,000,铁定超时?(时限是4S)
你被表面的现象迷惑了,现在我们一步一步来处理这个问题
问题一:得到输入的数据后,按照 Y 值排序,需要做怎样的处理
答:需要存储这个查询的原始输入 ID 号,这个大家都懂,不多说了问题二:如果枚举某一个 X 和 Y 情况的值,怎么算?
答:我们建立一个临时的求和数组,Sum[ maxN ],其中 maxN = 300,000我们这样处理
首先,memcpy(Sum, A, sizeof(A));
然后,i 从 1 枚举到 N, 当 i > Y 时, Sum[ i ] = Sum[ i ] + Sum[ i - Y ];
定义:maxK = (N - X)/ Y,表示前述 K 取得的最大值,那么最后的结果是不是就是 Sum[ X + K * Y ]呢?
因为容易知道
Sum[ X + K * Y] = A[ X + K * Y ] + Sum[ X + (K - 1) * Y ] = ... = A[ X + K * Y ] + A[ X + (K - 1) * Y ] + ... + A[ X + Y ] + Sum[ X ] = A[ X + K * Y ] + A[ X + (K - 1) * Y ] + ... + A[ X + Y ] + A[ X ]
所以,你轻松的认为就是它了,是的,一般的就可以这么认为了,但是这里有一个小bug,那就是上式成立的默认条件是 X < Y
如果 X > Y, 那么 显然还有 Sum[ X ] = A[ X ] + Sum[ X - Y ],而这时候的 Sum[ X - Y ] 并不是我们需要的,所以这里我们需要特别判断处理了
问题三:如果当前的Y值和前一个Y值是相等的,那么怎么处理呢?(注意,已经按Y值排序,所以出现 Y值相等是可能的)
答:再看看问题二,我们从知道,当计算当前的查询的时候,前一个查询计算遗留了很多宝贵的财富,如 Sum 数组值,我们要好好利用这个 Sum 值容易知道,如果这次也枚举的话,那么显然得到的 Sum 数组值是和上一个是一模一样的,没有任何改变,只不过这时候我们需要的是确定 Sum[ * ]中 * 的值,结合前述
我们知道,就是老套路,只不过省略了求 Sum 数组的阶段了
问题四:解释什么是 “枚举前200个”
答:假设我们定义三元组(Xi, Yi, IDi)表示排序后的第 i 个存储的查询,这个查询在原始输入的时候,是排在 IDi 位的,注意,我们知道,是按照 Y 值排序的,所以,Y 值是非递减的 ,所以我们这里说的 “枚举前200个” 的这个 '200" 就是针对Y值而言的,也就是说,我们对前200个Y值采取枚举处理,注意,Y值相同,算1个,因为从前面知道,当当前的Y值和前一个Y值是相同的时候,那么计算当前的值时,完全可以O(1)得到答案。问题五:“枚举前200个”的复杂度是多少呢?
我们知道,前200是针对Y值得,所以,处理的Y值是不同的,我们有知道,Y值肯定是越小算的次数越多?是吗,肯定是的这样,我们不妨取最坏情况,假设前200个值是1,2,3,...,200。
好,那么 X 值怎么办呢?显然,X值肯定也是越小越好(自己想想),但是X值可不是离散有序的,所以我们假设是最坏情况,即假设前200个有 X = 1
那么,问题就明朗了,在这种最坏的情况下,需要多大的复杂度呢?
容易计算通项公式:T(i) = (N - Xi) / Yi,所以有
第1个:(N - 1) / 1
第2个:(N - 1)/ 2
第3个:(N - 1)/ 3
...
第200个:(N - 1)/ 200
所以总的时间复杂度是:T = (N - 1)* (1 + 1 / 2 + 1 / 3 + 1 / 4 + ... + 1 / 200) = 299,999 * 《*》
编程计算《*》约为 5.878030948,所以可以计算 T 的值约为 1763403,可以初步估计是 2000000,大约是 10 的 6 次方数量级
换句话说,枚举计算前200个的时间复杂度大约是 10^6 数量级,显然,这是可以接受的
问题六: 200个以后的怎么处理呢?
答:这个问题问得好,这里采取的方式就是赤裸裸的枚举了,如下所示ans = 0; while( X <= N ) ans += A[X], X += Y;
问题七:不用我说,你都知道,这时候的200个以后的复杂度又是多少呢?
答:这时候我们才去的措施仍然是最坏计算,我们假定前200个不存在 Y 值相同的,而200个以后的全是相同的,且值为 201,“这是为什么呢?”因为 Y 值越小越好,故此
同样的,我们假定所有的 X 值均为1,“这是为什么呢?” ,理由同上。
好了,现在计算总的复杂度:
第201个:(300000 - 1) / 201
第202个:(300000 - 1) / 201
...
第300000个:(300000 - 1)/ 201
所以,T = (300000 - 1)* { (300000 - 201 + 1)/ 201 },计算其值约为 447461195,即约为 4.5 * 10^8,差不多是 “4.5亿”
这样的复杂度,计算机也是可以承受的
总结:所以,这样一来,总的时间复杂度大约为 4.5亿左右(450,000,000),计算机是扛的住的,何况这只是最坏的情况,数据有随机生成,就更快了。
所以,有时候,粗略的直觉未必可信,计算之后,才发现科学才是硬道理。
#include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> using namespace std; const int maxN = 3 * 100000 + 2; struct node { int s, t, idx; inline void in() { scanf("%d %d", &s, &t); } inline bool operator<(const node &tmp) const { return t < tmp.t; } }; static int nQ; // total Queries static node Q[maxN]; // i know you have known static int nA; // total Numbers static int A[maxN]; // like before typedef long long i64d; static i64d ans[maxN]; // note answers static i64d sum[maxN]; // sum[x + k*y] = A[x + k*y] + sum[x + (k-1)*y] int main() { //freopen("data.in", "r", stdin); //freopen("data.out", "w", stdout); while( scanf("%d", &nA) == 1 ) { for(int i = 1; i <= nA; ++i) scanf("%d", A + i); scanf("%d", &nQ); for(int i = 0; i < nQ; ++i) Q[i].idx = i, Q[i].in(); sort(Q, Q + nQ); static int nT, pre_t; nT = pre_t = 0; for(int i = 0, j; i < nQ; ++i) { if( Q[i].t != pre_t && nT <= 200 ) { ++nT, pre_t = Q[i].t; for(j = 1; j <= nA; ++j) { sum[j] = A[j]; if( j > Q[i].t ) sum[j] += sum[j - Q[i].t]; } } if( Q[i].t == pre_t ) { ans[ Q[i].idx ] = sum[ Q[i].s + (nA - Q[i].s) / Q[i].t * Q[i].t ]; if( Q[i].s > Q[i].t ) ans[ Q[i].idx ] -= sum[ Q[i].s - Q[i].t ]; } else { ans[ Q[i].idx ] = 0LL; for(j = Q[i].s; j <= nA; j += Q[i].t) ans[ Q[i].idx ] += A[ j ]; } } for(int i = 0; i < nQ; ++i) printf("%I64d\n", ans[i]); } return 0; }
相关文章推荐
- Codeforces Beta Round #92 (Div. 1 Only)
- Codeforces Beta Round #69 (Div. 2 Only)——A,B,D
- Codeforces Beta Round #69 (Div. 1 Only) C. Beavermuncher-0xFF 树上贪心
- Codeforces Beta Round #18 (Div. 2 Only)——A
- Codeforces Beta Round #18 (Div. 2 Only) D - Seller Bob
- Codeforces Beta Round #75 (Div. 1 Only) A题
- Codeforces Beta Round #92 (Div. 2 Only) B. Permutations
- Codeforces Beta Round #92 (Div. 2 Only) B. Permutations 模拟
- Codeforces Beta Round #6 (Div. 2 Only) D. Lizards and Basements 2 dp
- Codeforces Beta Round #75 (Div. 2 Only) A题
- Codeforces Beta Round #6 (Div. 2 Only) A. Triangle 水题
- Codeforces Beta Round #73 (Div. 2 Only)——A,B,C
- Codeforces Beta Round #87 (Div. 2 Only) A题
- Codeforces Beta Round #69 (Div. 2 Only) E题
- Codeforces Beta Round #75 (Div. 1 Only) B. Queue 线段树。单点更新
- Codeforces Beta Round #75 (Div. 1 Only)---B.Queue
- Codeforces Beta Round #18 (Div. 2 Only)——C
- Codeforces Beta Round #85 (Div. 1 Only) C (状态压缩或是数学?)
- Codeforces Beta Round #6 (Div. 2 Only)
- Codeforces Beta Round #16 (Div. 2 Only)——C