[POJ2115 C Looooops]拓展欧几里得算法

【算法分析】
实际上是解这样一个方程:
A+C*x=B  (mod 2^k)
C*x=B-A   (mod 2^k)
C*x+(2^k)*y=B-A
注意如果B-A<0的话,要+2^k使之变回>=0。
现在引入小写的a,b,c,并令a=C,b=2^k,c=B-A。
然后求方程ax+bx=c的最小整数解。
于是用拓展欧几里得算法获得ax+bx=gcd(a,b)的解,然后弄到x的最小非负整数解出来即可。
【其他】
第一次深切了解了这个算法。
【CODE】
#include using namespace std;
typedef __int64 lld;
lld A,B,C,k,x,y,P,gcd;

lld exgcd(lld a,lld b){
if (!b){
x=1; y=0;
return a;
}
lld res=exgcd(b,a%b),tx=x,ty=y;
x=ty; y=tx-a/b*ty;
return res;
}

lld solve(lld a,lld b,lld c){
if (!c) return 0;
if (!a) return -1;
lld gcd=exgcd(a,b);
if (c%gcd) return -1;
a/=gcd; b/=gcd; c/=gcd;
x*=c; y*=c;
x=(x%b+b)%b;
return x;
}

int main(){
lld a,b,c;
while (cin >> A >> B >> C >> k){
if (!A && !B && !C && !k) break;
P=1;
for (int i=1;i<=k;i++) P*=2;
a=C; b=P; c=(((B-A)%P)+P)%P;
x=0; y=0;
lld ans=solve(a,b,c);
if (ans==-1) cout << "FOREVER" << endl;
else cout << ans << endl;
}
}

[BZOJ1316 树上的询问]关于树的基于点的划分

【题目地址】http://61.187.179.132:8080/JudgeOnline/showproblem?problem_id=1316
【解题经历】
其实我做这题是有一段曲折的经历的。。。
第一次见面是由于师傅在ACM_DIY群里说在衡阳八中的OJ上见到了ACRush。。。于是果断跑过去围观。
一看~晕,用PASCAL的ACRush。。。假。。。
然后围观他做的那题——就是本题了。。。
于是我苦思冥想~最终没有任何想法,果断GG。。。
然后后来由于我想做男人…于是围观了漆大神的论文,YY了一下,把树上基于点的分治领悟了一下.
然后就把男人八题里相关的那题AC了.今日突然想起这题.再次来围观,额,终于有想法了.
然后一开始WA到SB。
写了个朴素来随机对拍。没错啊~= =
然后猛然发现如果他给出的长度是0,是必须Yes的。而我的是No。
改完一交,TLE。。。万念俱灭啊。。。
然后回去做了一节晚修的作业,突然有灵感,上来一改,果然AC。还排第二,不错呢。
【算法分析】
先将树根据点的数量分割,分成很多份(有点像线段树),然后再从小份的到大份的弄回来处理。
分割复杂度:O(N lg N)
处理的话就直接枚举给出的LEN。一个一个分开判断,然后在判的时候排一下序,
排这个序的总复杂度变成O(N lg^2 N)。
利用单调性可以做到O(Qt) per 分割树节点的复杂度。其中Qt表示该分割树区间的点的数量。

然后我们来围观一下TLE的原因:
我把枚举给出的询问放在solve的外面,于是复杂度变成O(QN lg^2 N) 其中Q为询问个数。
于是,
我们把枚举给出的询问放在solve的排序后面,复杂度就变成O(N lg^2 N+QN lg N)。
于是终于AC!
【其他】
好弱啊。。。YM GP大神。
大家也可以去围观提交记录,确实是ACRush在提交。。。表示没有撒谎~
另外程序中的big是因为有一段时间WA到不行,全部改成long long了。
后来改回来就继续用big了~
【CODE】
#include #include #include #include #include using namespace std;
typedef int big;
const big N=10005;
const big INF=0x7FFFFFFF;
struct edge{big x,y;big c;edge *next;}g[2*N],*ls[N];
struct PobigType{big dep,l,r,root;}tr[N*20];
big n,Qn,e,PN,Qt,CT;
big pl[20][N],color[20][N],size[N],tot[20],Q[N];
big dis[N],Que[N];
bool result[N];

void add(big x,big y,big c){
e++;
g[e].x=x; g[e].y=y; g[e].c=c; g[e].next=ls[x]; ls[x]=&g[e];
}

void input(){
e=0;
for (big i=1;i<=n;i++) ls[i]=NULL;
scanf("%d%d",&n,&Qn);
big x,y,c;
for (big i=1;i scanf("%d%d%d",&x,&y,&c);
add(x,y,c);
add(y,x,c);
}
memset(tot,0,sizeof(tot));
PN=1; CT=1;
for (big i=1;i<=n;i++) pl[1][i]=i;
}

void makelabel(big p,big fa,big &times,big *co){
size[p]=times++;
for (edge *t=ls[p];t;t=t->next)
if (t->y!=fa && co[t->y]==co[p]){
dis[t->y]=dis[p]+t->c;
makelabel(t->y,p,times,co);
}
size[p]=times-size[p];
}

void choose_root(big p,big fa,big *co,big &root,big &cost,big &total){
big NowCost=total-size[p];
for (edge *t=ls[p];t;t=t->next)
if (t->y!=fa && co[t->y]==co[p]) NowCost=max(NowCost,size[t->y]);
if (NowCost cost=NowCost;
root=p;
}
for (edge *t=ls[p];t;t=t->next)
if (t->y!=fa && co[t->y]==co[p])
choose_root(t->y,p,co,root,cost,total);
}

void AddPoint(big p,big fa,big *PL,big &TOT,big *co){
PL[++TOT]=p;
for (edge *t=ls[p];t;t=t->next)
if (t->y!=fa && co[p]==co[t->y])
AddPoint(t->y,p,PL,TOT,co);
}

void Div(big pos,big l,big r,big dep){
PobigType *p=&tr[pos];
big times=0,cost=INF,i,*co=color[dep];
p->l=l; p->r=r; p->dep=dep;
for (i=l;i<=r;i++) co[pl[dep][i]]=CT;
if (l>=r){
PN–;
return;
}
dis[l]]=0;
makelabel(pl[dep][l],0,times,co);
choose_root(pl[dep][l],0,co,p->root,cost,size[l]]);
for (edge *t=ls[p->root];t;t=t->next)
if (co[t->y]==co[p->root]){
big L=tot[dep+1]+1;
AddPoint(t->y,p->root,pl[dep+1],tot[dep+1],co);
big R=tot[dep+1];
PN++; CT++;
Div(PN,L,R,dep+1);
}
}

inline bool Qcmp(int x,int y){
return dis[x]}

void solve(){
for (big pos=PN;pos>=1;pos–){
PobigType *p=&tr[pos];
big times=0;
dis[p->root]=0;
makelabel(p->root,0,times,color[p->dep]);
Qt=0;
for (big i=p->l;i<=p->r;i++)
Q[++Qt]=pl[p->dep][i];
sort(Q+1,Q+Qt+1,Qcmp);
for (big k=1;k<=Qn;k++) if (!result[k]){
big ans=Que[k],j=0;
for (big i=1;i<=Qt;i++){
if (dis[Q[i]]>ans) break;
while (j+1 while (j && dis[Q[j]]+dis[Q[i]]>ans) j–;
while (j && color[p->dep+1][Q[j]]==color[p->dep+1][Q[i]]) j–;
if (j && dis[Q[j]]+dis[Q[i]]==ans){
result[k]=true;
break;
}
}
}
}
}

int main(){
input();
Div(1,1,n,1);
for (big i=1;i<=Qn;i++){
scanf("%d",&Que[i]);
if (!Que[i]) result[i]=true;
}
solve();
for (big i=1;i<=Qn;i++)
if (result[i]) printf("Yesn");
else printf("Non");
return 0;
}

ZOJ比赛——2010.4.10

这次比赛首先说肥闽是来打酱油的。。。
他一题都没出,果然是酱油君。(上一次好像也是)

下面发一段他说的话:
徒弟  18:56:08
还不是你们两只……都把水题a了……一题也不剩给我,bs
徒弟  18:56:29
明明3道水题……应该1人一道……或者你不做才对的嘛
徒弟  18:56:38
抢哥的水题……日……

说说比赛流程:
首先FHN前40分钟秒了A和E。除了Orz我还能说什么呢。。。

然后这之后我这个水B居然在最后一题上WA了1次。为什么呢?原因是如果N!=M的时候,我没有把边读完
好吧,1WA,1A。
然后,我去搞第三题。因为当时看了一下,觉得比较有FEEL。但是看看AC人数:1。
但是我还是上了。。。
于是——1A。。。哈哈。。。我还是这题程序速度最快的那个。
然后,肥闽和FHN,已经把F题的题意参详出来了。
他们表示没啥想法,我一看。。。这题根本我就做过= =。
而且那题数据规模还大一些,但是建图有点不同而已。
于是迅速敲完,5题搞定。
值得注意的是:肥闽一直在搞第二题,但是他直到酱油瓶都满了,还没有AC,最后,我们悲剧地停在5题上。。。
最后rank:22
http://acm.zju.edu.cn/onlinejudge/showContestRankList.do?contestId=307
排名围观地址。。。
最后总结:这次没有到6,ULT没有出来就GG了,主要原因是:肥闽

[POJ 1744 Elevator Stopping Plan]贪心、二分答案、男人8题

【题目大意】

N个人从1楼想上楼,然后电梯上一层需要4s,停下以后,再次启动,需要10s。人走一层需要20s。

问最少需要多少时间使得所有人都到达自己家。

【算法分析】

二分答案,然后贪心,每次让电梯走得尽量高就行。

【其它】

WA超多次。就因为电梯停下是不需要时间的。那10s是它再次启动的时间。

7/8个男人。。。但是最后一题:An old Stone Game

MS非常牛X

【CODE】

#include

[POJ1737 Connected Graph]组合数学、男人8题

【题目大意】

给定N个标号为1~N的点,让你求出对于这N个点,连一些边使得它成为无向连通图的方案有多少种。

【算法分析】

= =看了一下别人的思考过程。。。公式还是自己推的。。。

要利用补集思想,首先连边方案一共有2^(n*(n-1)/2)这么多种。(每条边取或者不取)

然后我们以于1连通的点的个数i为划分状态。

ans[n]=2^(n*(n-1)/2)-Q;

Q=SUM(ans[i]*C(i-1,n-1)*2^((n-i)*(n-i-1)/2))   1<=i

就是固定住1这个点,然后在剩下的n-1个点里取i-1个,总共i个点是1的联通块上的。

然后i个点的连通图有ans[i]这么多方案,所以乘起来,然后根据乘法原理,剩下有n-i个点,

能构成2^((n-i)*(n-i-1)/2)种方案,也都乘起来。

【其他】1A

跑得非常慢,在最后一面= =

【CODE】

#include #include #include using namespace std;
const int ml=372;

int n;
int C[55][55][ml+1];
int ans[55][ml+1];
int cf[1311][ml+1];
int tmp[ml+1],tmp2[ml+1];

struct BNT{
       void plus(int *x,int *y){
            for (int i=1;i<=ml;i++) x[i]+=y[i];
            for (int i=1;i                x[i+1]+=x[i]/10;
                x[i]%=10;
            }
       }

       void mul(int *x,int *y){
            memset(tmp,0,sizeof(tmp));
            for (int i=1;i<=ml;i++)
              for (int j=1;i+j-1<=ml;j++) tmp[i+j-1]+=x[i]*y[j];
            for (int i=1;i                tmp[i+1]+=tmp[i]/10;
                tmp[i]%=10;
            }
       }

       void dec(int *x,int *y){
            for (int i=1;i<=ml;i++) x[i]-=y[i];
            for (int i=1;i                while (x[i]<0){x[i]+=10; x[i+1]--;}
                while (x[i]>9){x[i]-=10; x[i+1]++;}
            }
       }
}Big;

void deal(int m){
     memcpy(ans[m],cf[m*(m-1)/2],sizeof(ans[m]));
     for (int i=1;i         Big.mul(ans[i],C[m-1][i-1]);
         memcpy(tmp2,tmp,sizeof(tmp));
         int q=m-i;
         Big.mul(tmp2,cf[q*(q-1)/2]);
         Big.dec(ans[m],tmp);
     }
}

void init(){
     memset(C,0,sizeof(C));
     memset(cf,0,sizeof(cf));
     C[0][0][1]=1;
     for (int i=1;i<=50;i++)
       for (int j=0;j<=i;j++){
           if (j) Big.plus(C[i][j],C[i-1][j-1]);
           Big.plus(C[i][j],C[i-1][j]);
       }
     cf[0][1]=1;
     for (int i=1;i<=1300;i++){
         for (int j=1;j<=ml;j++) cf[i][j]=cf[i-1][j]*2;
         for (int j=1;j             cf[i][j+1]+=cf[i][j]/10;
             cf[i][j]%=10;
         }
     }
     for (int i=1;i<=50;i++)
       deal(i);
}

void output(){
     int i=ml;
     while (!ans[n][i]) i–;
     for (int j=i;j>=1;j–) printf("%d",ans[n][j]);
     printf("n");
}

int main(){
    init();
    while (cin >> n && n) output();
}