20181029 考试记录
T1:简单$dfs$
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; inline int read() { int f=1,ans=0;char c; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return f*ans; } int a1[80],b1[80],a2[80],b2[80]; int n,m,num[102]; bool check(){ int ans=0; for(int i=0;i<=12;i++){ if(num[i]>0) ans+=num[i]; if(!num[i]) break; } if(ans==n+m) return 1; return 0; } void dfs(int pos) { if(check()){ cout<<"Yes"; exit(0); return; } if(pos==m+1) return; if(!a2[pos]) { dfs(pos+1); return; } dfs(pos+1); for(int i=1;i<=n;i++){ if(b1[i]!=0){ int t2=b2[pos],t1=b1[i];num[b1[i]]--;num[b2[pos]]--; b1[i]-=a2[pos]; if(b1[i]<0) b1[i]=0; num[b1[i]]++; b2[pos]-=a1[i]; if(b2[pos]<0) b2[pos]=0; num[b2[pos]]++; dfs(pos+1); num[b2[pos]]--; num[b1[i]]--; b1[i]=t1; b2[pos]=t2; num[b2[pos]]++; num[b1[i]]++; } } } int main() { freopen("defile.in","r",stdin); freopen("defile.out","w",stdout); n=read(),m=read(); for(int i=1;i<=n;i++) a1[i]=read(),b1[i]=read(),num[b1[i]]++; for(int i=1;i<=m;i++) a2[i]=read(),b2[i]=read(),num[b2[i]]++; dfs(1); cout<<"No"; return 0; }
T2:
(垃圾题目,$getchar$换成$scanf$,就$100 score$了)
$k\leq 15$,所以想到可以用状压$dp$来解决,第一步是要求每两个宝藏之间的距离,假设起点也是一个宝藏,用$bfs$解决,然后问题就转换成在一个完全图中选择$x$个点,使经过一次后距离不超过$T$,最大的$x$是多少。所以考虑状压$dp$,但是当只有一位($dp(i)$ 表示当前状态时是有后效性的,所以考虑二维)。
设$dp(i,j)$表示当前取到的状态为$i$,最后一个点是$j$的最小距离。然后看一下当前距离是否小于$t$,若小于然后统计一下状态里的$1$即可.$dp(i,j)=dp(u,p)+dis(p,j) $,然后就瞎搞了
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; inline int read() { int f=1,ans=0;char c; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return f*ans; } int n,m,k,t; int a[512][512]; struct node{ int x,y; }p[21]; int sx,sy,sry=1,has[512][512],vis[512][512],dis[21][21]; struct node1{ int x,y,ans; }; queue<node1> que; int dx[4]={1,-1,0,0}; char str1[510]; int dy[4]={0,0,1,-1}; int dp[125537][21],d[21],inf=99999999,ans; int main() { n=read(),m=read(),k=read(),t=read(); for(int i=1;i<=n;i++){ scanf("%s",str1+1); for(int j=1;j<=m;j++){ char str=str1[j]; if(str=='#') a[i][j]=0; else a[i][j]=1; if(str=='*'){p[++sry].x=i,p[sry].y=j;has[i][j]=sry;} if(str=='S'){p[1].x=i,sx=i,sy=j,p[1].y=j;has[i][j]=1;} } getchar(); } memset(dis,127/3,sizeof(dis)); for(int st=1;st<=sry;st++){ int px=p[st].x,py=p[st].y; memset(vis,0,sizeof(vis)); while(!que.empty()) que.pop(); node1 pig; pig.ans=0,pig.x=px,pig.y=py; vis[px][py]=1; que.push(pig); while(!que.empty()){ int xx=que.front().x,yy=que.front().y,ff=que.front().ans;que.pop(); for(int i=0;i<4;i++){ int tx=dx[i]+xx,ty=dy[i]+yy; if(tx>=1&&tx<=n&&ty>=1&&ty<=m){ if(vis[tx][ty]) continue; if(!a[tx][ty]) continue; vis[tx][ty]=1; node1 fff; fff.x=tx,fff.y=ty,fff.ans=ff+1; que.push(fff); if(has[tx][ty]){ dis[st][has[tx][ty]]=fff.ans; } } } } } memset(dp,127/3,sizeof(dp)); dp[1][1]=0; for(int i=1;i<=(1<<sry)-1;i++){ memset(d,0,sizeof(d)); int st=0; for(int j=1;j<=sry;j++){ if(i&(1<<(j-1))) d[j]=1,st++; } for(int j=1;j<=sry;j++){ if(!d[j]) continue; d[j]=0; int zz=0,disdis=inf; for(int z=1;z<=sry;z++) zz+=(d[z]*(1<<(z-1))); for(int z=1;z<=sry;z++){ if(d[z]) dp[i][j]=min(dp[i][j],dp[zz][z]+dis[z][j]); } d[j]=1; if(dp[i][j]<=t) ans=max(ans,st); } } cout<<ans-1<<endl; }
T3:
其实就是一道比较简单的$dp$,结果看错了$A_i$的范围
首先,先离散化,lower_bound即可,确定一下每个数,就是把他们存到$1~n$中。然后看见题目上说的是最小的最大,果断二分答案。我们假设$x$为二分的最小值,所以对于每一个位置$pos$,我们先设$st[pos]$表示右端点为$pos$的最小$l$值满足在$l~pos$中没有相同的数,其实就是这道题(this)。所以$pos$上一块的取值范围是$[st[pos]-1,pos-i]$,我们设$g(i)$表示前$i$个音符已经划定的方案数,及从$\sum_{i=l}^r g(i)$,当前复杂度$O(n^2)$,考虑到$\sum_{i=l}^r g(i)$这个式子可以前缀和优化,所以$dp$总复杂度$O(n)$,时间复杂度:$O(nlog(n))$
#include<iostream> #include<cstdio> #include<cstring> #define mod 998244353 #include<algorithm> #define int long long using namespace std; inline int read() { int f=1,ans=0;char c; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return f*ans; } int g[525011],sumg[525011],n,a[525011],x[525011],st[525011],last[525011]; inline int get(int lim){ memset(g,0,sizeof(g)),memset(sumg,0,sizeof(sumg)); g[0]=sumg[0]=1; for(int i=1;i<=n;i++){ int l=st[i]-1,r=i-lim; if(l>r) g[i]=0; else{ if(l==0) g[i]=sumg[r]; else g[i]=sumg[r]-sumg[l-1]; } g[i]=(g[i]+mod)%mod; sumg[i]=sumg[i-1]+g[i]; sumg[i]=(sumg[i]+mod)%mod; }return g[n]%mod; } bool check(int mid){return get(mid);} int maxn; signed main() { freopen("instrument.in","r",stdin); freopen("instrument.out","w",stdout); n=read(); for(int i=1;i<=n;i++) x[i]=a[i]=read(); sort(x+1,x+n+1); for(int i=1;i<=n;i++) a[i]=lower_bound(x+1,x+n+1,a[i])-x; for(int i=1;i<=n;i++){ st[i]=max(st[i-1],last[a[i]]+1); last[a[i]]=i; } int l=1,r=n; while(l<=r){ int mid=l+r>>1; if(check(mid)) maxn=max(maxn,mid),l=mid+1; else r=mid-1; } cout<<maxn<<endl<<(get(maxn)+mod)%mod; return 0; }