HDU_Steps9.2 杂题 HDU2052 HDU1871 HDU1254 HDU3350 HDU3234 HDU2642 HDU2833 HDU3483

来源:互联网 发布:c语言中的string.h 编辑:程序博客网 时间:2024/05/16 02:04
HDU2052 Picture

HDU1871 无题

上面两道纯水题。。为什么Steps做到这中间还有这么水的题=。=

HDU1254 推箱子

推箱子模型,最短路使用DFS加回溯,更新找到箱子的最小值,搜索人可达的位置用BFS,人和箱子的位置共同组成一个状态。

#include<cstdio>#include<string.h>#include<queue>using namespace std;int cas,m,n,sr,sc,er,ec,pr,pc,ans;bool flag;int map[10][10],dvis[10][10][10][10];int dr[]={0,-1,0,1};int dc[]={1,0,-1,0};bool outr(int x){return x<0||x>=m;}bool outc(int x){return x<0||x>=n;}//传入新旧人的位置以及箱子的位置bool bfs(int opr,int opc,int npr,int npc,int a,int b){if(opr==npr&&opc==npc)return true;queue<pair<int,int> > q;int bvis[10][10];memset(bvis,0,sizeof bvis);q.push(make_pair(opr,opc));bvis[opr][opc]=1;while(!q.empty()){int r=q.front().first,c=q.front().second;q.pop();for(int i=0;i<4;i++){int nr=r+dr[i],nc=c+dc[i];if(nr<0||nc<0||nr>=m||nc>=n||bvis[nr][nc])continue;//墙和箱子的位置是不可走的if(map[nr][nc]==1||(nr==a&&nc==b))continue;bvis[nr][nc]=1;if(nr==npr&&nc==npc)return true;q.push(make_pair(nr,nc));}}return false;}void dfs(int obr,int obc,int opr,int opc,int step){//上一步箱子和人的位置,以及走的步数if(step>ans)return;//这里注意剪枝if(obr==er&&obc==ec){ans=min(step,ans);flag=true;//标记成功到达return;}for(int i=0;i<4;i++){//算出新的人和新的箱子的位置int npr=obr+dr[i],npc=obc+dc[i];int nbr=obr+dr[(i+2)%4],nbc=obc+dc[(i+2)%4];if(outr(nbr)||outr(npr)||outc(nbc)||outc(npc))continue;//出界了if(map[nbr][nbc]==1||map[npr][npc]==1)continue;//人或者箱子要去的位置有墙if(!bfs(opr,opc,npr,npc,obr,obc))continue;//人不能走到那个位置if(dvis[npr][npc][nbr][nbc]==1)continue;//已经到达过这个状态dvis[npr][npc][nbr][nbc]=1;dfs(nbr,nbc,npr,npc,step+1);dvis[npr][npc][nbr][nbc]=0;}return;}int main(){scanf("%d",&cas);while(cas--){scanf("%d%d",&m,&n);for(int i=0;i<m;i++){for(int j=0;j<n;j++){scanf("%d",&map[i][j]);if(map[i][j]==2)sr=i,sc=j;if(map[i][j]==4)pr=i,pc=j;if(map[i][j]==3)er=i,ec=j;}}flag=false;ans=10000000;memset(dvis,0,sizeof dvis);dfs(sr,sc,pr,pc,0);//传入箱子和人的位置if(flag==false){printf("-1\n");}else{printf("%d\n",ans);}}return 0;}


HDU3350 #define is unsafe

给定一个只含有MAX和+操作的式子,求加法运行了多少次,其中MAX使用宏定义。注意一个规律,对于MAX(A,B)其中A中加a次,B中加b次若A>B,则加a*2+b次,否则a+b*2次。然后用递归处理这个字符串就可以了。

#include<cstdio>#include<string>#include<iostream>using namespace std;struct state{state(int a,int b){s=a,k=b;}int s,k;//和,次数};state find(string str){int in=0,len=str.length(),num=0;//当前位置,字符串长度if(str[in]>='0'&&str[in]<='9'){//第一个字母是整数,读取这个数while(in<len&&str[in]>='0'&&str[in]<='9')num=num*10+str[in++]-'0';if(in>=len)return state(num,0);//如果只剩一个数,直接返回else{//只能是a+B的形式,B是一个式子,处理B段state st=find(str.substr(in+1));return state(num+st.s,st.k+1);}}else if(str[in]=='M'){in+=4;int cnt=1,mid=0;while(cnt>0){//匹配MAX()右括号的位置,并找出对应这个MAX的逗号的位置if(str[in]=='(')cnt++;else if(str[in]==')')cnt--;if(str[in]==','&&cnt==1)mid=in;in++;}state le=find(str.substr(4,mid-4));//求MAX(A,B)中的Astate ri=find(str.substr(mid+1,in-mid-2));//求MAX(A,B)中的Bint p1,p2;if(le.s>ri.s){p1=le.s;p2=le.k*2+ri.k;}else{p1=ri.s;p2=le.k+ri.k*2;}if(in>=len-1){//已经到达末端return state(p1,p2);}else{//MAX(A,B) + C的形式,求Cstate st=find(str.substr(in+1));//处理加号后面的部分return state(p1+st.s,st.k+p2+1);}} }int main(){int cas;char str[1005];cin>>cas;while(cas--){cin>>str;state rs=find(str);cout<<rs.s<<" "<<rs.k<<endl;}return 0;}

HDU3234 Exclusive-OR

这题并查集真恶心啊。。首先a^a=0,a^0=a,虚拟一个父节点,将所有已知的连接到这个父节点上来,用一个数组记录该节点异或父节点的值,最后如果是偶数个则父节点被异或偶数次,不影响结果,如果为奇数次并且父节点不是虚拟节点的话就无法得到答案了。如果在同一个集合中但是结果与当前值冲突就是wrong了~

#include<cstdio>#include<string.h>#include<algorithm>using namespace std;int n,q;int p[20005],va[20005],map[20005];void init(int x){    for(int i=0;i<=x;i++){        p[i]=i;        va[i]=0;    }    }int find(int x){    int t=p[x];    if(x!=p[x]){        p[x]=find(p[x]);        va[x]^=va[t];//x^p[x]=va[x],p[x]^p[px]=va[p[x]],所以x^p[p[x]]=va[x]^va[p[x]]    }    return p[x];    }bool merge(int x,int y,int v){    int px=find(x);    int py=find(y);    if(px==py){        if((va[x]^va[y])!=v)return false;        return true;        }    if(px==n)swap(px,py);//n为虚拟节点,已知的都连到n上    p[px]=py;    //x^px=va[x],y^py=va[y],x^py=v;    //所以px^py=va[x]^va[y]^v    va[px]=va[x]^va[y]^v;    p[px]=py;    return true;}int main(){    char op,s[1000],cas=1;int a[20];    while(scanf("%d%d",&n,&q),n||q){        gets(s);        init(n+1);        printf("Case %d:\n",cas++);        int nqs=0,tmpas,num;        bool right=true;        while(q--){            gets(s);            tmpas=0,num=0;            op=s[0];            //不正确就可以结束了            if(!right)continue;            int len=strlen(s);            for(int i=2;i<len;i++){//输入数字,数字数量不确定                if(s[i]>='0'&&s[i]<='9')num=num*10+s[i]-'0';                else{                    a[tmpas++]=num;                    num=0;                }            }            a[tmpas++]=num;            if(op=='I'&&tmpas==2){//I p v,p和n合并                right=merge(a[0],n,a[1]);                nqs++;            }else if(op=='I'&&tmpas>2){                right=merge(a[0],a[1],a[2]);                nqs++;            }else if(op=='Q'){                int ans=0;                memset(map,0,sizeof map);                for(int i=1;i<tmpas;i++){//a^a=0这种直接排除                    map[find(a[i])]++;                    ans=(ans^va[a[i]]);                }                bool f=1;                for(int i=1;i<tmpas;i++){                    int t=find(a[i]);                    if(map[t]%2!=0&&t!=n){//假设x和y的和都是t,x^t^y^t=t^y,t被抵消掉,但如果奇数次,t未知并且未被抵消就不能得到答案                        printf("I don't know.\n");                        f=0;                        break;                    }                }                if(f){                    printf("%d\n",ans);                }            }            if(!right){                printf("The first %d facts are conflicting.\n",nqs);            }        }        printf("\n");    }    return 0;    }

HDU2642 Stars 

裸的二维树状数组加上简单的容斥原理

#include<cstdio>#include<string.h>#include<algorithm>using namespace std;int c[1002][1002];bool v[1002][1002];int lowbit(int x){return x&(-x);}void modify(int x,int y,int p){for(int i=x;i<=1001;i+=lowbit(i)){for(int j=y;j<=1001;j+=lowbit(j)){c[i][j]+=p;}}}int sum(int x,int y){int s=0;for(int i=x;i>0;i-=lowbit(i)){for(int j=y;j>0;j-=lowbit(j)){s+=c[i][j];}}return s;}int main(){int m,x1,x2,y1,y2;char op[3];while(scanf("%d",&m)!=EOF){memset(v,false,sizeof v);memset(c,0,sizeof c);while(m--){scanf("%s",op);if(op[0]=='B'){scanf("%d%d",&x1,&x2);x1++,x2++;if(v[x1][x2])continue;v[x1][x2]=true;modify(x1,x2,1);}else if(op[0]=='D'){scanf("%d%d",&x1,&x2);x1++,x2++;if(!v[x1][x2])continue;v[x1][x2]=false;modify(x1,x2,-1);}else{scanf("%d%d%d%d",&x1,&x2,&y1,&y2);x1++,x2++,y1++,y2++;if(x1>x2)swap(x1,x2);if(y1>y2)swap(y1,y2);printf("%d\n",sum(x2,y2)+sum(x1-1,y1-1)-sum(x1-1,y2)-sum(x2,y1-1));}}}return 0;}


HDU2833 WuKong

好题,求两条最短路中最多能公共几个点。首先容易证明公共最短路必然连续,然后用floyd求出每两点之间的最短路。如果d[st][en]=d[st][i]+d[i][j]+d[j][en],说明d[i][j]是最短路的一部分。c[i][j]代表两点之间最短路的条数。

#include<cstdio>#include<algorithm>using namespace std;const int inf=200000000;int d[305][305],c[305][305];//有一个性质,如果有公共最短路,则公共最短路一定是连续的(可以用反证法证明)//Floyd后,如果i和j在最短路上则有d[s][e]=d[s][i]+d[i][j]+d[j][e]int main(){int n,m,u,v,w,s1,s2,t1,t2;while(scanf("%d%d",&n,&m),n||m){for(int i=0;i<=n;i++){for(int j=0;j<=n;j++){d[i][j]=(i==j)?0:inf;c[i][j]=0;}}for(int i=0;i<m;i++){scanf("%d%d%d",&u,&v,&w);if(d[u][v]<w)continue;d[u][v]=d[v][u]=w;c[u][v]=c[v][u]=1;}scanf("%d%d%d%d",&s1,&t1,&s2,&t2);//Folyd,其中c[i][j]表示两点间最短路的条数最大有多少条for(int k=1;k<=n;k++){for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){if(d[i][j]>d[i][k]+d[k][j]){d[i][j]=d[i][k]+d[k][j];c[i][j]=c[i][k]+c[k][j];}if(d[i][j]==d[i][k]+d[k][j]&&c[i][j]<c[i][k]+c[k][j]){c[i][j]=c[i][k]+c[k][j];}}}}//DPint rs=-1;//可能只有一个交点;for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){if(d[s1][i]+d[i][j]+d[j][t1]==d[s1][t1]&&d[s2][i]+d[i][j]+d[j][t2]==d[s2][t2]){rs=max(rs,c[i][j]);}}}printf("%d\n",rs+1);}return 0;}


HDU3483 A Very Simple Problem

求sigma(x^k*k^x),k<2*1e9,x<50,又是一道恶心的构造矩阵,解释在注释中

#include<cstdio>#include<string.h>using namespace std;/*求sum(x^k*k^x) k=1~N * x^(k+1)*(k+1)^x=x^k*x*(k+1)^x 然后用二项式定理展开(k+1)^x即可 * 例如当x=4时   * | 1x  0  0  0  0  0 | |x^k*k^0| |x^(k+1)*(k+1)^0| * | 1x 1x  0  0  0  0 | |x^k*k^1| |x^(k+1)*(k+1)^1| * | 1x 2x 1x  0  0  0 |*|x^k*k^2|=|x^(k+1)*(k+1)^2| * | 1x 3x 3x 1x  0  0 | |x^k*k^3| |x^(k+1)*(k+1)^3| * | 1x 4x 6x 4x 1x  0 | |x^k*k^4| |x^(k+1)*(k+1)^4| * | 1x 4x 6x 4x 1x 1x | | S(k)  | |     S(k+1)    | */typedef __int64 ll;const int maxn=55;ll c[maxn][maxn],n,m,x;void init(){//初始化二项式系数memset(c,0,sizeof c);for(int i=1;i<maxn;i++){c[i][1]=c[i][i]=1;for(int j=2;j<=i-1;j++){c[i][j]=c[i-1][j-1]+c[i-1][j];if(c[i][j]>=m)c[i][j]%=m;}}}struct mat{ll a[maxn][maxn];mat(int type){//0是全0矩阵,2是单位矩阵,1是构造的矩阵memset(a,0,sizeof a);if(type==0)return;if(type==2){for(int i=0;i<x+2;i++)a[i][i]=1;return;}for(int i=0;i<x+2;i++){for(int j=0;j<=i;j++){if(i!=x+1){a[i][j]=c[i+1][j+1]*x;if(a[i][j]>=m)a[i][j]%=m;}else a[i][j]=a[i-1][j];}}a[x+1][x+1]=1;}mat mult(mat b){mat rs(0);for(int i=0;i<x+2;i++){for(int j=0;j<x+2;j++){for(int k=0;k<x+2;k++){rs.a[i][j]=rs.a[i][j]+a[i][k]*b.a[k][j];if(rs.a[i][j]>=m)rs.a[i][j]%=m;}}}return rs;}int getr(){ll r=0;for(int i=0;i<x+2;i++){r+=x*a[x+1][i];}return r%m;}};mat binMat(int k){//非递归的二分求解矩阵,递归栈溢出mat m(1),tmp(2);while(k){if(k&1)tmp=tmp.mult(m);m=m.mult(m);k>>=1;}return tmp;}int main(){while(scanf("%I64d%I64d%I64d",&n,&x,&m)){if(n==-1)break;init();mat m=binMat(n-1);printf("%d\n",m.getr());}return 0;}



原创粉丝点击