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)中的A
state ri=find(str.substr(mid+1,in-mid-2));//求MAX(A,B)中的B
int 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的形式,求C
state 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];
}
}
}
}
//DP
int 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;
}