A.一直一个长度为n的序列,求对于相邻i,j,abs(a[i]-a[j])<=h的子数列个数%9901(n<=100000,h<=1000000000)(5.21)
首先离散化,然后考虑dp,dp[i]=sigma(dp[j]) (abs(dp[i]-dp[j])<=h) 然后上树状数组优化。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define N 100005
#define Mo 9901
#define ll long long
using namespace std;
int a[N],b[N],c[N],tmp[N],n,h;
ll ans[N];
int lowbit(int x){return x&-x;}
int binary_search1(int l,int r,int x){
while(l<r){
int mid=(l+r)>>1;
if(b[mid]<x) l=mid+1;
else r=mid;
}
return l;
}
int binary_search2(int l,int r,int x){
while(l<r){
int mid=(l+r)>>1;
if(b[mid]<=x) l=mid+1;
else r=mid;
}
return l-1;
}
void add(int pos,int x){
while(pos<N){
c[pos]+=x;
pos+=lowbit(pos);
}
}
ll getsum(int pos){
ll ret=0;
while(pos){
ret+=c[pos];
pos-=lowbit(pos);
}
return ret;
}
int main(){
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
while(~scanf("%d%d",&n,&h)){
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
memset(tmp,0,sizeof(tmp));
memset(ans,0,sizeof(ans));
int cnt=0;
ll res=0;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),tmp[i]=a[i];
sort(tmp+1,tmp+1+n);
for(int i=1;i<=n;i++)
if(tmp[i]!=tmp[i-1])
b[++cnt]=tmp[i];
//for(int i=1;i<=n;i++) printf("%d ",b[i]);puts("");
for(int i=1;i<=n;i++){
int x=binary_search1(1,cnt+1,max(a[i]-h,0));
int y=binary_search2(1,cnt+1,a[i]+h);
int now=binary_search2(1,cnt+1,a[i]);
//printf("%d %d %d\n",x,y,now);
ans[i]+=getsum(y)-getsum(x-1);
ans[i]%=Mo;
//printf("*%d\n",ans[i]);
add(now,ans[i]+1);
res+=ans[i];res%=Mo;
}
printf("%lld\n",res);
}
return 0;
}
B.求次短路。
正反两次求最短路,每局每条边,设当前枚举边为(u,v,w),则ans=min(ans,dis1[u]+w+dis2[v]) (dis1[u]+w+dis2[v]!=dis1[n])(5.21)
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#define inf 0x7fffffff
#define N 100005
using namespace std;
struct E {int to,nxt,w;}edge[N*2];
int n,r,tot=1;
int dis[2][N],u[N],v[N],w[N],idx[N];
bool vis[N];
queue<int>q;
void addedge(int from,int to,int w){
edge[tot].to=to;edge[tot].w=w;edge[tot].nxt=idx[from];idx[from]=tot++;
}
void spfa(int s,int t,int o){
memset(dis[o],127,sizeof(dis[o]));
memset(vis,0,sizeof(vis));
dis[o][s]=0;vis[s]=0;q.push(s);
while(!q.empty()){
int x=q.front();q.pop();vis[x]=0;
for(int t=idx[x];t;t=edge[t].nxt){
E e=edge[t];
if(dis[o][x]+e.w<dis[o][e.to]){
dis[o][e.to]=dis[o][x]+e.w;
if(!vis[e.to]) q.push(e.to),vis[e.to]=1;
}
}
}
}
int main(){
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
scanf("%d%d",&n,&r);
int x,y,ww;
for(int i=1;i<=r;i++)
scanf("%d%d%d",&x,&y,&ww),addedge(x,y,ww),addedge(y,x,ww),u[i]=x,v[i]=y,w[i]=ww;
spfa(1,n,0);
spfa(n,1,1);
int ans=inf;
for(int i=1;i<=r;i++){
int x=u[i],y=v[i],ww=w[i];
if(dis[0][x]+dis[1][y]+ww!=dis[0][n])
ans=min(ans,dis[0][x]+dis[1][y]+ww);
x=v[i];y=u[i];
if(dis[0][x]+dis[1][y]+ww!=dis[0][n])
ans=min(ans,dis[0][x]+dis[1][y]+ww);
}
printf("%d\n",ans);
return 0;
}
C.静态区间第k小。(5.23)
听说有种划分树。。写的主席树。。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<map>
#include<algorithm>
#define N 100005
using namespace std;
map<int,int>mp;
struct seg{
int ls,rs,l,r,num;
}t[2400000];// 4*N + NlogN
int root[N],a[N],b[N];
int n,m,cnt;
void init_build(int k,int l,int r){
t[k].l=l;t[k].r=r;
if(l==r) return;
int ls=++cnt,rs=++cnt;
t[k].ls=ls;t[k].rs=rs;
int mid=(l+r)>>1;
init_build(ls,l,mid);
init_build(rs,mid+1,r);
}
void modify(int k,int x){
int l=t[k].l,r=t[k].r;
int mid=(l+r)>>1;
if(l==r) {t[k].num++;return;}
if(x<=mid){
t[k].num++;
t[++cnt]=t[t[k].ls];
t[k].ls=cnt;
if(t[k].ls) modify(t[k].ls,x);
}
if(x>=mid+1){
t[k].num++;
t[++cnt]=t[t[k].rs];
t[k].rs=cnt;
if(t[k].rs) modify(t[k].rs,x);
}
}
void query(int a,int b,int k,int &ret){
int lsa=t[a].ls,lsb=t[b].ls;
int rsa=t[a].rs,rsb=t[b].rs;
if(t[a].l==t[a].r) {ret=t[a].l;return;}
if(t[lsb].num-t[lsa].num>=k)
query(lsa,lsb,k,ret);
else query(rsa,rsb,k-(t[lsb].num-t[lsa].num),ret);
}
int main(){
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),b[i]=a[i];
sort(b+1,b+1+n);cnt=0;
for(int i=1;i<=n;i++)
if(!mp.count(b[i])){
mp[b[i]]=++cnt;
b[cnt]=b[i];
}
cnt=1;root[0]=1;
init_build(1,1,mp[b[n]]);
//for(int i=1;i<=20;i++) printf("%d %d %d %d %d %d\n",i,t[i].l,t[i].r,t[i].ls,t[i].rs,t[i].num);
for(int i=1;i<=n;i++){
root[i]=++cnt;
t[root[i]]=t[root[i-1]];
modify(root[i],mp[a[i]]);
}
for(int i=1;i<=m;i++){
int l,r,k,ret;
scanf("%d%d%d",&l,&r,&k);
query(root[l-1],root[r],k,ret);
printf("%d\n",b[ret]);
}
//for(int i=1;i<=35;i++) printf("%d %d %d %d %d %d\n",i,t[i].l,t[i].r,t[i].ls,t[i].rs,t[i].num);
return 0;
}
D.长度为20的01序列,可以对一个数进行一次操作,操作是这个数及其相邻的数字取反。问这个01序列变成全0序列。保证有解。(5.21)
000101……1左边的0一定要翻,所以就每局从左还是从右翻……
#include<iostream>
#include<cstdio>
using namespace std;
int a[21],b[21],ans1,ans2;
int main(){
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
for(int i=1;i<=20;i++) scanf("%d",&a[i]),b[i]=a[i];
for(int i=1;i<=18;i++){
if(a[i]==0) continue;
a[i]^=1;a[i+1]^=1;a[i+2]^=1;
ans1++;
}if(a[19]+a[20]==2) ans1++;
for(int i=20;i>=3;i--){
if(b[i]==0) continue;
b[i]^=1;b[i-1]^=1;b[i-2]^=1;
ans2++;
}if(b[1]+b[2]==2) ans2++;
printf("%d\n",min(ans1,ans2));
return 0;
}
F.在m*n的地图上有一些障碍,求使已知三点连通的最小路径长度。(m,n<=100)(5.21)
最小的路径长度一定是三条路交于一个点,枚举这个点即可。
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#define N 105
#define inf 1<<30
using namespace std;
struct node{int x,y;};
int dirx[5]={0,1,-1,0,0};
int diry[5]={0,0,0,-1,1};
int dis[4][N][N];
bool vis[N][N];
char map[N][N];
int n,m;
queue<node>q;
void bfs(int x,int y,int o){
q.push((node){x,y});
dis[o][x][y]=0;
vis[x][y]=1;
while(!q.empty()){
node now=q.front();q.pop();
for(int i=1;i<=4;i++){
int nx=now.x+dirx[i];
int ny=now.y+diry[i];
if(nx&&nx<=n&&ny&&ny<=m&&map[nx][ny]!='X'&&!vis[nx][ny]){
q.push((node){nx,ny});
vis[nx][ny]=1;
dis[o][nx][ny]=dis[o][now.x][now.y]+1;
}
}
}
}
int main(){
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
while(~scanf("%d%d",&n,&m)){
int x[4],y[4],cnt=0;
memset(dis,255,sizeof(dis));
for(int i=1;i<=n;i++){
scanf("%s",map[i]+1);
for(int j=1;j<=m;j++)
if(map[i][j]=='F'||map[i][j]=='J'||map[i][j]=='Q')
x[++cnt]=i,y[cnt]=j;
}
//for(int i=1;i<=cnt;i++) printf("%d %d\n",x[i],y[i]);
for(int i=1;i<=3;i++){
memset(vis,0,sizeof(vis));
bfs(x[i],y[i],i);
}
int res=inf;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
bool flag=0;int ans=0;
for(int k=1;k<=3;k++){
if(dis[k][i][j]==-1) {flag=1;break;}
ans+=dis[k][i][j];
}
if(!flag) res=min(res,ans-2);
}
if(res==inf) printf("Impossible\n");
else printf("%d\n",res);
}
return 0;
}