您的位置:首页 > 其它

08-24 HDU2601求因数 HDU2604二分矩阵递归 USACO4.1.4D边构图DFS求环

2011-08-24 16:34 567 查看
鉴于昨天做多校联合的试题受的打击太大,今天早上在HDOJ挂了一套菜鸟赛的题目...虽然是菜鸟题目,但是对我这只小菜鸟,还是很有收获的

A题很水,阴在字符串读取上..C题原始背包..D题高中物理题,公式忘得差不多了..不过回忆了半天总算是过了,主要写一下B题和E题吧

HDU 2601 http://acm.hdu.edu.cn/showproblem.php?pid=2601

B题是求N因数个数的题目,一开始直接用LogN的枚举,过是过了..但是效率实在是太低了..

想到了分解质因数,N=a1^k1*a2^k2*a3*k3 则因数个数M=(a1+1)(a2+1)(a3+1).

但我写的那个分解质因数效率实在不怎么高,看了学长的程序,果然差距还是很大啊..虽然只是一个小优化,效率已经是天壤之别了..

#include <iostream>
using namespace std;
typedef long long LL;
LL fun(LL n)
{
LL ans=1,i;
for(i=2;i*i<=n;i++)
{
if(n%i==0)
{
int s=0;
while(n%i==0)
{
n/=i;//改变N的大小 会使循环次数快速减小
s++;
}
ans*=(s+1);
}
}
if(n>1) ans*=2;//这里注意一下
return ans;
}
int main()
{
LL n;
int cas;
scanf("%d",&cas);
while(cas--){
cin>>n;
n++;
cout<<(fun(n)-1)/2<<endl;
}
return 0;
}


HDU 2604 http://acm.hdu.edu.cn/showproblem.php?pid=2604

E题是一题递归题,递归方程不难想出,但是效率也是很低啊..

请教学长,原来递归可以用二分矩阵优化,看了一下67大牛的文章,受益颇多.http://www.matrix67.com/blog/archives/276/

例如对于f(n) = 4f(n-1) - 3f(n-2) + 2f(n-4) ,右上n-1的矩阵里对角线填1,第n行填递推系数,然后利用结合律二分计算矩阵,



对于这一题,时间从4700MS+优化到了109MS,真的快了很多啊

矩阵相乘有不少需要注意的地方,

递推方程F
=F[N-1]+F[N-3]+F[N-4]

#include <cstdio>
using namespace std;
int st[5][5]={
{0,0,0,0,0},
{0,0,1,0,0},
{0,0,0,1,0},
{0,0,0,0,1},
{0,1,1,0,1},
};
struct jz{
int a[5][5];
//两种构造方法,一种清0,一种是相乘的矩阵
jz(int k){
if(k==0)for(int i=1;i<=4;i++)for(int j=1;j<=4;j++)a[i][j]=0;
if(k==1)for(int i=1;i<=4;i++)for(int j=1;j<=4;j++)a[i][j]=st[i][j];
}
//矩阵相乘,乘法过程中模m
jz mult(jz jz2,int m){
jz ans(0);
for(int i=1;i<=4;i++)
for(int j=1;j<=4;j++)
for(int k=1;k<=4;k++)
ans.a[i][j]=(ans.a[i][j]+a[i][k]*jz2.a[k][j])%m;
return ans;
}
//得到结果
int getr(){
return a[4][1]*2+a[4][2]*4+a[4][3]*6+a[4][4]*9;
}
};
jz dfs(int k,int m){
if(k==1)return jz(1);
//二分
jz rs=dfs(k/2,m);
jz ans=rs.mult(rs,m);
//处理为奇数的情况
if(k%2==1){
jz t2=jz(1);
jz tmp=ans.mult(t2,m);
ans=tmp;
}
return ans;
}

int main(){
int l,k;
int a[5]={1,2,4,6,9};
while(scanf("%d%d",&l,&k)!=EOF){
if(l<=4)printf("%d\n",a[l]%k);
else{
jz ans=dfs(l-4,k);
printf("%d\n",ans.getr()%k);
}
}
}


USACO 4.1.4 Fence Loopshttp://www.nocow.cn/index.php/Translate:USACO/fence6

单纯的找最小环不难,用DFS就可以了,这一题难在告诉你的是边之间的关系,而没有点..看了NOCOW上大牛的思路,用边构图,牛啊..要注意顺序,只能从边的这边进,然后从边的另一边出,存储的时候该边两端的边要分开储存,用一个dir数组表示两条边之间的关系..然后搜索的时候注意方向..

/*
ID: swm80232
PROG:fence6
LANG: C++
*/
#include <cstdio>
#include <string>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
int n,l[105][2][10],vis[105],res,dir[105][105],w[105];
void dfs(int s,int p,int len,int d){
if(len>=res)return;
for(int i=1;i<=l[p][1-d][0];i++){//搜这个点的另一端
int pi=l[p][1-d][i];
if(pi==s&&dir[s][p]==0){//一开始是从s->1端开始搜,所以最后结束是在s->0端才是环
res=min(res,len);
return;
}
if(!vis[pi]){
vis[pi]=1;
dfs(s,pi,len+w[pi],dir[pi][p]);//看p在现在点的哪一边(下次搜从另一边开始搜)
vis[pi]=0;
}
}
}
int main(){
freopen("fence6.in","r",stdin);
freopen("fence6.out","w",stdout);
memset(w,0,sizeof w);

int s,ls,n1s,n2s;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d%d%d",&s,&ls,&n1s,&n2s);
w[s]=ls;
l[s][0][0]=n1s;
l[s][1][0]=n2s;
for(int j=1;j<=n1s;j++){
scanf("%d",&l[s][0][j]);
dir[s][l[s][0][j]]=0;
}
for(int j=1;j<=n2s;j++){
scanf("%d",&l[s][1][j]);
dir[s][l[s][1][j]]=1;
}
}

res=1e8;
memset(vis,0,sizeof vis);
for(int i=1;i<=n;i++){
if(w[i]==0)continue;
//memset(vis,0,sizeof vis);
vis[i]=1;
dfs(i,i,w[i],0);//从s->该点为0端开始搜
vis[i]=0;
}
printf("%d\n",res);
// system("pause");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: