考前日常。。。
1、某种密码(password.*)
关于某种密码有如下描述:某种密码的原文A是由N个数字组成,而密文B是一个长度为N的01数串,原文和密文的关联在于一个钥匙码KEY。若KEY=∑▒〖Ai*Bi〗,则密文就是原文的一组合法密码。
现在有原文和钥匙码,请编一个程序来帮助他统计到底有多少个符合条件的密文。
【输入数据】
第一行两个数N,KEY,意义同题目描述;
第二行N个数表示原文A,意义同题目描述。
【输出数据】
一个数ANS,表示对于原文A和KEY,有多少组可行的密文B。
【输入样例】
3 2
1 1 2
【输出样例】
2
【样例说明】
密文110,1*1+1*1+0*2=2
密文001,0*1+0*1+1*2=2
一共两组可行的密文。
【数据约定】
60%数据满足N<=25
100%数据满足N<=40,-maxlongint<=∑▒Ai<=maxlongint
初看觉水;
思路历程:搜索(2^n ???)----》背包(maxint???)---》背包+hash(n的大小不允许我这样做)---》折半搜索+hash桶计(海星)
没什么说的了,下面是CPP
#include<bits/stdc++.h> using namespace std; //long long bao1[1200000],bao2[1200000]; int n,N; long long a[50],key,ji1=0; map<long long,int>hash; inline void dfs1(int pos,long long sum) { // if(sum>key)return ; if(pos==N) { // bao1[++ji1]=sum; // bao1[++ji2]=sum+a[pos]; hash[sum]++;hash[sum+a[pos]]++; return ; } dfs1(pos+1,sum+a[pos]); dfs1(pos+1,sum); } inline void dfs2(int pos,long long sum) { // if(sum>key)return ; if(pos==n) { // bao2[++ji2]=sum; // bao2[++ji2]=sum+a[pos]; ji1+=hash[key-sum];ji1+=hash[key-sum-a[pos]]; return ; } dfs2(pos+1,sum+a[pos]); dfs2(pos+1,sum); } int main() { // freopen("DDD.in","r",stdin); scanf("%d%lld",&n,&key); for(int i=1;i<=n;++i)scanf("%lld",&a[i]); // sort(a+1,a+n+1); N=n/2; dfs1(1,0); dfs2(N+1,0); // int ji1=(1<<N),ji2=(1<<(n-N-1)); // for(int i=1;i<=ji1;++i) // { // map[bao1[i]]++; // } // sort(bao1+1,bao1+ji1+1); // sort(bao2+1,bao2+ji2+1,PP); // int j=ji2,ans=0; // for(int i=1;i<=ji1;++i) // { // bool fla=0; // while(bao1[i]+bao2[j]>key) // { // j--; // } // while(bao1[i]+bao2[j]==key) // { // ans++;i++;j--;fla=1; // } // if(fla)i--; // } printf("%lld",ji1); return 0; } /* 40 5 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 */
注释的地方有一些剪枝,当然加了会有红紫;
2、球的序列(formation.*)
N个编号为1-n的球,每个球都有唯一的编号。这些球被排成两种序列,分别为A、B序列,现在需要重新寻找一个球的序列l,对于这个子序列l中任意的两个球,要求j,k(j<k),都要求满足lj在A中位置比lk在A中位置靠前,且lj在B中位置比lk在B中位置靠前,请你计算这个子序列l的最大长度。
输入:
第一行一个整数,表示N。
第二行N个整数,表示A序列。
第三行N个整数,表示B序列。
样例输入
5
1 2 4 3 5
5 2 3 4 1
样例输出
2
样例说明
L可以是{2,3},也可以是{2,4}
数据范围:
40% N<=5000
100% N<=50000
依旧是水的;
分吸分吸:如果对 Lj,Lk( j<k ) 有 ALj 在 ALk 前,且B Lj 在 B Lk 前;那么Lj,Lk 在A,B中相对位置不变;即LCS;
nlogn求:
#include<bits/stdc++.h> using namespace std; int read() { int x,f=0;char ch=getchar(); while(!isdigit(ch)){f=1;ch=getchar();} while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} return f?-x:x; } int f[50100],A[50100],B[50100],ma[50100],mb[50100],len,n; int che(int x) { int l=0,r=len+1,mid; while(l<r) { mid=((l+r)>>1); if(f[mid]>=x) { r=mid; } else { l=mid+1; } } return l; } int main() { // n=read(); // for(int i=1;i<=n;++i) // { A[i]=read(); ma[A[i]]=i; } // for(int i=1;i<=n;++i) // { B[i]=read(); mb[i]=ma[B[i]]; } freopen("formation.in","r",stdin); freopen("formation.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;++i) { scanf("%d",&A[i]);ma[A[i]]=i; } for(int i=1;i<=n;++i) { scanf("%d",&B[i]);mb[i]=ma[B[i]]; } f[1]=mb[1]; len=1; for(int i=2;i<=n;++i) { if(mb[i]>f[len]) { len++;f[len]=mb[i]; } else { int pos=che(mb[i]); f[pos]=mb[i]; } } printf("%d",len); return 0; }
3、大逃亡(escape.*)
给出数字N(1<=N<=10000),X(1<=x<=1000),Y(1<=Y<=1000),代表有N个敌人分布一个X行Y列的矩阵上,矩形的行号从0到X-1,列号从0到Y-1再给出四个数字x1,y1,x2,y2,代表你要从点(x1,y1)移到(x2,y2)。在移动的过程中你当然希望离敌人的距离的最小值最大化,现在请求出这个值最大可以为多少,以及在这个前提下,你最少要走多少步才可以回到目标点。注意这里距离的定义为两点的曼哈顿距离,即某两个点的坐标分为(a,b),(c,d),那么它们的距离为|a-c|+|b-d|。
输入:
第一行给出数字N,X,Y
第二行给出x1,y1,x2,y2
下面将有N行,给出N个敌人所在的坐标
输出:
在一行内输出你离敌人的距离及在这个距离的限制下,你回到目标点最少要移动多少步。
Sample input
2 5 6
0 0 4 0
2 1
2 3
Sample output
2 14
题意在明示二分与敌人最小距离......;
1st:floodfill(BFS)处理每个点与最近敌人的距离;
2nd:二分与敌人最小距离再BFS寻终点;
时间:O(log(n+m)*(n+m)+n+m)(当然是口胡了)
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> using namespace std; bool mark[1010][1010]; int map[1010][1010]; int x[5000010],y[5000010]; int bs[1010][1010]; int n,m,k,tou,wei,qx,qy,zx,zy; int dx[4]={0,0,1,-1}; int dy[4]={1,-1,0,0}; void init() { int i,a,b; scanf("%d%d%d",&k,&n,&m); tou=1;wei=0; scanf("%d%d%d%d",&qx,&qy,&zx,&zy); qx++;qy++;zx++;zy++; for(i=1;i<=k;i++) { scanf("%d%d",&a,&b); a++;b++; wei++;x[wei]=a;y[wei]=b; mark[a][b]=1; } } void bfs() { int i,nx,ny,xx,yy,p; while(tou<=wei) { xx=x[tou];yy=y[tou];tou++; for(p=0;p<4;p++) { nx=xx+dx[p];ny=yy+dy[p]; if(nx<1 || nx>n || ny<1 || ny>m) continue; if(!mark[nx][ny]) { mark[nx][ny]=1;map[nx][ny]=map[xx][yy]+1; wei++;x[wei]=nx;y[wei]=ny; } } } } bool check(int mid) { int i,xx,yy,nx,ny,p; tou=1;wei=1;x[1]=qx;y[1]=qy; memset(mark,0,sizeof(mark)); memset(bs,127,sizeof(bs)); mark[qx][qy]=1;bs[qx][qy]=0; while(tou<=wei) { xx=x[tou];yy=y[tou];tou++; for(p=0;p<4;p++) { nx=xx+dx[p];ny=yy+dy[p]; if(nx<1 || nx>n || ny<1 || ny>m || map[nx][ny]<mid) continue; if(!mark[nx][ny]) { mark[nx][ny]=1;bs[nx][ny]=bs[xx][yy]+1; wei++;x[wei]=nx;y[wei]=ny; } } } if(mark[zx][zy]) return 1; else return 0; } int main() { freopen("escape.in","r",stdin); freopen("escape.out","w",stdout); init(); bfs(); int l=0,r=map[qx][qy],mid; while(l+1<r) { mid=(l+r)>>1; if(check(mid)) l=mid; else r=mid; } if(check(r)) {cout<<r<<" "<<bs[zx][zy]<<endl;} else {check(l);cout<<l<<" "<<bs[zx][zy]<<endl;} // system("pause"); return 0; }
如果真爱有颜色,那么一定是红橙黄紫深蓝吧;