CodeForces#24

额。。我发现CodeForces比TopCoder更接近OI。。感到很有意思。。以后要多关注这个地方了。。

Problem A:
水题。。我写了个Dfs爆搜非常的繁琐。。幸好1A了。。
Problem B:
模拟题这题折磨了我很久。。我大量使用了map和vector,不知道哪个地方出错了。。改了半天最后做完C之后才A掉这个。。
Problem C:
这题比B好做多了。。直接循环到一定程度就可以直接计算了。。
Problem E:
一开始我在那边写E因为我感觉这个就是一个最大斜率啊。。可惜对这方面不熟悉哎囧。。不是很会搞。。以后要补一下了囧。。。求(x-x’)/(v-v’)的最小值,就是倒数的最大值。。。。然后应该可以做。。但是我水平太烂写不出来囧。。
Problem D:
这题最神奇了!!!我完全不能相信我居然过了!!

Ural 1752 Tree 2

题目很简洁。。做法也容易。。就是有点烦。。
很显然你要知道是否要输出0,必须知道从某点开始的最长路径,显然可以Dp之。。
然后干脆对每个询问都在最长路径上找点。。
对每个点记录2^k的祖先就可以准确的找到点。。就没问题了。。。
Code:
超过最大长度。。
www.ideone.com/I5fn5

无聊弄出来的Lca算法。。。

   天天在弯销油西。。。颓废万分。。晚上总算去水了道题。。我无聊中想出一个很SB的Lca。。。
就是把这颗树树链剖分(不用线段树的,只需要记录每个点对应当路径的最高点)。。。
然后考虑u和v的Lca(假设u的深度大于v)。。如果在同一条链中就是v。。
否则的话设u的路径最高点要深于v的路径最高点,那么显然Lca不可能在u的路径中,将u换成u的路径最高点的父节点。。。然后就这递归下去。。。
额。。时间复杂度LogN。。预处理复杂度是O(N)的。。常数又比线段树那个要小。。速度比记录2^k祖先那个和线段树都要快一些。。树链剖分还可以写Bfs..拒绝爆stack。。还是挺不错滴(*^__^*) 嘻嘻。。。
Code:(题目是Ural上的Tree)
#include <vector>
#include <algorithm>
#include <utility>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <set>
#include <map>
#include <cstring>
#include <time.h>
#define rep(i,n) for(int i=0;i<n;i++)
#define pb push_back
#define Debug(x) cout<<#x<<"="<<x<<endl;
#define For(i,l,r) for(int i=l;i<=r;i++)
#define tr(e,x) for(eit e=x.begin();e!=x.end();e++)
#define printTime cout<<"Time:"<<pre-clock()<<endl;pre=clock();
const int inf=~0U>>1,maxn=50000;
using namespace std;
int n,q;
struct Edge
{
int t,c;
Edge(int _t,int _c):t(_t),c(_c){}
};
vector<Edge> E[maxn];
typedef vector<Edge>::iterator eit;
void AddEdge(int s,int t,int c)
{
E[s].pb(Edge(t,c));
E[t].pb(Edge(s,c));
}
void Init()
{
scanf("%d",&n);int s,t,c;
rep(i,n-1)
{
scanf("%d%d%d",&s,&t,&c);
AddEdge(s,t,c);
}
}
int D[maxn],C[maxn],F[maxn],Size[maxn];
int Q[maxn],h,t,Own[maxn];
void BFS(int vs)
{
h=t=0;
for(Q[t++]=vs,F[vs]=-1,D[vs]=0,C[vs]=0;h<t;h++)
{
int x=Q[h];
tr(e,E[x])if(e->t!=F[x])
{
F[e->t]=x;C[e->t]=C[x]+e->c;
D[e->t]=D[x]+1;Q[t++]=e->t;
}
}
for(int i=h-1;i>=0;i–)
{
int x=Q[i];Size[x]=1;
tr(e,E[x])if(e->t!=F[x])Size[x]+=Size[e->t];
}
memset(Own,-1,sizeof Own);
for(int i=0;i<h;i++)
{
int a=Q[i];
int x=a,next;if(Own[x]>=0)continue;
for(;;x=next)
{
next=-1;Own[x]=a;
tr(e,E[x])if(e->t!=F[x])
if(next==-1||Size[e->t]>Size[next])
next=e->t;
if(next==-1)break;
}
}
}
int Lca(int u,int v)
{
for(;;)
{
if(D[u]<D[v])swap(u,v);
if(Own[u]==Own[v])return v;
if(D[Own[u]]<D[Own[v]])swap(u,v);
u=F[Own[u]];
}
}
int Query(int u,int v)
{
int lca=Lca(u,v);
return C[u]+C[v]-2*C[lca];
}
void Solve()
{
scanf("%d",&q);int u,v;
rep(i,q)
{
scanf("%d%d",&u,&v);
printf("%dn",Query(u,v));
}
}
int main()
{
//freopen("in","r",stdin);
Init();
BFS(0);
Solve();
}

SPOJ QTREE3

这个变态题目。。有N种做法。。能AC的MS不多囧。。
做法系列1:
思路:从下往上对每个节点维护一个平衡树,然后用平衡树来回答第K大大问题
A:平衡树+启发式合并,两颗平衡树合并直接暴力把小的插进大的。。每个最多被插LogN次。。总共就是O(NLogN^2+QLogN)。。极难AC。。我Treap TLE,SBT也TLE。因为我SBT写得太烂了。。
B:Splay合并,Splay可以做到在O(NLogN)完成合并。。然后Splay常数较大,还是TLE。。。
C:注意题目的特性。。首先就是Q比N小很多,就是说许多结点都不需要维护平衡树,先先序遍历这个树,然后一些节点要插入的话直接用先序遍历中的区间插入。。再设个常数如果一个节点中最大的子树实在太小的话插入也麻烦干脆直接重新建个平衡树好。。估计可以勉强AC。。不过可能很困难吧。。我一直觉得可能可以弄个阀值仿照IOI2009的Region搞出来。。不过很麻烦。。
做法系列2:
思路:从小到大加入每个数,对每个节点维护还需要+几个数就可以输出了。。然后每次都可以取路径中的最小值,如果是0的话就输出,然后变成下一个。。一个节点显然只能影响的它的所有祖先。。所以需要维护路径。。
A:维护路径,还要最小值,直接上动态树,我的动态树写得太烂了。。无法AC。。。
B:维护路径也可以树链剖分啊,还是TLE。。。
做法系列3:
思路:TMD,干脆忽略这个树直接上区间K大值的算法好了,当然要先先序遍历一下了。。
A:一般的先二分在用线段树的做法肯定TLE O(NLogN+QLogN^3)..
B : 有一种二分树就是对所有权值建树,然后每个节点储存当前权值区间中的所有数在序列中的位置。。那么可以LogN得到节点区间中L到R之间的树的个数,就可以在LogN^2完成2分了。。写的好一点可以AC。。。
C:还有一种很NB的划分树,可以在NLogN+QLogN的时间解决问题。。非常NB啊。。具体看www.notonlysuccess.com/ 还不会写哎。。不过应该可以AC。。。

SRM 476

哎。。真是一场失败的SRM。。Rating没变囧。。
Level I
这么一道水题我只有235分。。实际上只要枚举就行了。但比赛前最后3分钟我发现我的KawiEdit不能用了晕。。结果拼命抢修。。修好后一慌张手速就慢了。。而且我看到这题后立马写二分。。脑缺死了。。n这么小干嘛不枚举啊晕。。
Level II
这个题目太恶心了。。本来我想的完全正确啊。。代码也没有错(一开始我一直以为我概率搞错。。最后发现是题目恶心)。。注意到每个人的friend字符串在36个字符以下。。那么算一下可以发现一个人最多有15个朋友。。关键是题目中有一句话说主人公只会访问自己的朋友。。所以顶点数最多16!!!靠。。
那么就简单了设Dp(Vised,int last)表示访问过了Vised的人,最后一个是last。。首先枚举下一个是哪个。。然后按概率排序。。显然第i个被主人公选择的情况只可能是前i-1个都不幸悲剧了。。第i个又OK。。那么算出这个概率然后+起来就OK了。。
Level III
额。。这题实际上不是非常难啊晕。。我当时完全没有时间去做了悲剧。。
首先注意到这个图是个仙人掌,所以一条边要么是桥要么在一个环里面额。。是桥的话显然要是crewSize。。否则的话考虑这个环,加入这个环离出口最近的是0,其它一次标号为1..n,那么首先如果没有Cabin的话,设L[x]是x到x-1,R[x]是x到x+1的Cabin数量,显然L[x]+R[x]>=crewSize。并且如果L[x]>L[x-1]完全没意义。。所以L[x]<=L[x-1]同理R[x]<=R[x+1]..然后现在有一些Cabin。。那么就跟一个经典问题就是把一个数列通过最小的变换变成单调类似了。。注意到降低显然不需要费用。。那么就OK了。。

原创题[X哥的泡妞计划]

应某人要求将名字改成X哥。。扯蛋的时候现编的题目。。感觉很有意思啊。。
2.X哥的泡妞计划
(paoniu.in/paoniu.out)
英俊潇洒玉树临风的X哥要开始泡妞啦!X哥看上了N个妞比如XX,XXX,XXXX,泡妞,当然是要花钱滴!第i个妞要花掉X哥Vi的钱,可有些女生之间风格差别太大比如XX和XXXX,X哥无法适应囧,因此就不能一起泡啦,有M对这样的女生,第i对是ai和bi。。X哥的母亲知道了这个消息,觉得自己儿媳妇自然是越多越好。。于是给了X哥V的钱,让X哥去泡妞!X哥最多能泡几个妞呢?
数据范围
N<=100 X哥看上的女生不会太多。。
M<= 200
V<= 1000
输入:
第一行是N和M和V
第二行有N个数,分别是Vi
之后每行一对ai和bi

SGU 261. Discrete Roots

给一个素数p,整数k和a
就x^k=a(mod p)的所有整数解。。。
首先算出原根g
设x=g^i(mod p)
则首先若a==0(我就是忘处理这个所以WAN次囧。。)。。那么答案就是0.。
否则a=g^j(mod p)
那么g^(ik)=g^j
<=> ik=j(mod p-1)..
算出所有满足这个的i,代入得到所有x,排序就OK了。。
Code:
#include <vector>
#include <algorithm>
#include <utility>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <set>
#include <map>
#include <cstring>
#include <time.h>
#define rep(i,n) for(int i=0;i<n;i++)
#define pb push_back
#define Debug(x) cout<<#x<<"="<<x<<endl;
#define tr(e,x) for(typeof(x.begin()) e=x.begin();e!=x.end();e++)
const int inf=~0U>>1,maxn=20;
using namespace std;
typedef long long ll;
ll P[maxn],m=0,p,g,k,a;
void decompose(ll x)
{
for(ll i=2;i*i<=x;i++)
if(x%i==0)
{
P[m++]=i;
while(x%i==0)x/=i;
}
if(x>1)P[m++]=x;
}
ll ext_gcd(ll a,ll b,ll&x,ll&y)
{
if(!b){x=1;y=0;return a;}
ll tmp=ext_gcd(b,a%b,y,x);y-=x*(a/b);
return tmp;
}
ll pow(ll x,ll e)
{
if(!e)return 1;
ll tmp=pow(x,e/2);tmp*=tmp;tmp%=p;
if(e&1)tmp*=x,tmp%=p;
return tmp;
}
ll inv(ll x)
{
return pow(x,p-2);
}
bool IsRoot(ll a)
{
rep(i,m)
if(pow(a,(p-1)/P[i])==1)return false;
return true;
}
void FindRoot()
{
decompose(p-1);
for(ll i=2;i<p;i++)if(IsRoot(i)){g=i;break;}
}
ll discrete_Log(ll a)
{
map<ll,ll> Map;ll M=sqrt(p)+1;
ll v=inv(pow(g,M));
ll e=1;Map[1]=0;
for(ll i=1;i<M;i++){e=e*g%p;if(!Map.count(e))Map[e]=i;}
for(ll i=0;i<M;i++)
{
if(Map.count(a))return i*M+Map[a];
a=a*v%p;
}
return -1;
}
vector<ll> Solve(ll a,ll b,ll m)
{
ll x,y,d;
d=ext_gcd(a,m,x,y);
vector<ll> A;
if(b%d)return A;
ll t=b/d;x%=m;if(x<0)x+=m;x=x*t%m;
rep(i,d)
{
A.pb(x);
x+=m/d;x%=m;
}
return A;
}
int main()
{
//freopen("in","r",stdin);
cin>>p>>k>>a;
if(a==0){cout<<1<<endl<<0<<endl;return 0;}
FindRoot();
ll Loga=discrete_Log(a);
vector<ll> Logx=Solve(k,Loga,p-1);
cout<<Logx.size()<<endl;
vector<ll> Ans;
tr(it,Logx)
{
ll tmp=pow(g,*it);
Ans.pb(tmp);
}
sort(Ans.begin(),Ans.end());
tr(it,Ans)cout<<*it<<endl;
}