B. Inna and Nine
题意:给一个长度为1e5的数字串,如果相邻两个数相加等于9就可以把这两个数合并为9,问在9的个数最多的情况下,最后的结果有几种
思路:4545这种串如果长度为偶数,那么合并的答案是唯一的,如果45454长度为奇数的串,合并的方法有floor(len/2)+1,处理出有多少段,最后相乘
代码:
#include <bits/stdc++.h> using namespace std; const int maxn=1e5+7; char a[maxn]; int b[maxn]; int stk[maxn]; int top; int main() { scanf("%s",a+1); int len=strlen(a+1); long long ans=1; for(int i=1;i<=len;i++){ b[i]=a[i]-'0'; } for(int i=2;i<=len;){ if(b[i]+b[i-1]==9){ int res=2; for(int j=i+1;j<=len;j++){ if(b[j]+b[j-1]==9){ res++; if(j==len)i=j+1; } else{ i=j+1; break; } } stk[++top]=res; } else i++; } for(int i=1;i<=top;i++){ if(stk[i]&1)ans*=stk[i]/2+1; } cout<<ans<<endl; return 0; } /* 45454 */
C. Inna and Dima
题意:给一种1000*1000的地图,可以从任何一个地方开始,按照DIMA这种顺序走,最多走过多少个DIMA,如果死循环打印Poor Inna!,如果不能走打印Poor Dima!,可以走打印最多几次
思路:对每个字母D都遍历一下,走过的地方记忆化,记忆化搜索
代码:
#include <bits/stdc++.h> using namespace std; const int maxn=1005; char mp[maxn][maxn]; int vis[maxn][maxn]; int ans[maxn][maxn]; int dx[5]={1,-1,0,0}; int dy[5]={0,0,1,-1}; int n,m; bool ok=false; char gett(int x,int y) { if(mp[x][y]=='D')return 'I'; if(mp[x][y]=='I')return 'M'; if(mp[x][y]=='M')return 'A'; if(mp[x][y]=='A')return 'D'; } int dfs(int x,int y) { if(ans[x][y]!=-1)return ans[x][y]; int res=0; for(int i=0;i<4;i++){ int xx=x+dx[i],yy=y+dy[i]; if(xx<1||xx>n||yy<1||yy>m||gett(x,y)!=mp[xx][yy])continue; if(vis[xx][yy]){ ok=true; return 0; } vis[xx][yy]=1; res=max(res,dfs(xx,yy)); vis[xx][yy]=0; } ans[x][y]=res+1; return ans[x][y]; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ cin>>mp[i][j]; } } memset(ans,-1,sizeof(ans)); int res=0; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(mp[i][j]=='D'){ vis[i][j]=1; res=max(res,dfs(i,j)); vis[i][j]=0; } } } res/=4; if(ok) puts("Poor Inna!"); else if(res==0)puts("Poor Dima!"); else cout<<res<<endl; return 0; }
D. Inna and Sequence
题意:有一个空序列,下面有两种操作,操作一是在字符串的末尾加0或加入1,第二种操作是删除当前字符串的第ai位字符(1<=i<=m)数组a会输入,每次删除都要把数组a中存在的位都删掉,两种操作最多1e6次,数组a长度1e6
思路:因为字符串长度最长为1e6,所以最多删除1e6次,用几个一棵线段树维护字符串,一个维护区间[L,R]中还剩几个字符,一个是没有被删除的字符串的每一位插入的是什么
最后最多删除1e6次,插入也是1e6次,复杂度是nlogn
代码:
#include <bits/stdc++.h> using namespace std; const int maxn=1e6+7; int n,m; int a[maxn]; int sum[maxn<<2],val[maxn<<2]; void update(int rt,int L,int R,int x,int pos) { if(L==R){ sum[rt]=1; val[rt]=x; // printf("test %d %d %d %d\n",L,R,val[rt],pos); return ; } int mid=(L+R)>>1; if(pos<=mid)update(rt<<1,L,mid,x,pos); else update(rt<<1|1,mid+1,R,x,pos); sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } void del(int rt,int L,int R,int pos) { if(L==R){ sum[rt]=0; return ; } int mid=(L+R)>>1; if(pos<=sum[rt<<1])del(rt<<1,L,mid,pos); else del(rt<<1|1,mid+1,R,pos-sum[rt<<1]); sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } void pri(int rt,int L,int R) { if(sum[rt]==0)return ; // printf("test %d %d %d\n",L,R,sum[rt]); if(L==R&&sum[rt]){ printf("%d",val[rt]); return ; } int mid=(L+R)>>1; pri(rt<<1,L,mid); pri(rt<<1|1,mid+1,R); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ scanf("%d",&a[i]); } int len=1; for(int i=1;i<=n;i++){ int op; scanf("%d",&op); if(op!=-1){ update(1,1,n,op,len++); } else{ for(int j=1;j<=m;j++){ if(a[j]-j+1>sum[1])break; // printf("test %d %d\n",j,sum[1]); del(1,1,n,a[j]-j+1); } } } if(sum[1]==0)puts("Poor stack!"); else{ pri(1,1,n); puts(""); } return 0; }
E. Inna and Babies
题意:有n(2000)个蓝点,m(2000)个红点,t秒后蓝点变为(x - t, y + t), (x + t, y - t).的线段,红点变为 (x + t, y + t), (x - t, y - t)的线段,为最少多少秒后会出现封闭的矩形
思路:对答案二分,二分到答案以后,先对所有的线段进行处理,把相交的线段合并为一条线段,然后外层枚举蓝色的线段,内层枚举那两条红色的线段I,j与它相交,在vis[i][j]的值加一,如果在加vis[i][j]的值前vis[i][j]已经有值 了,就表明现在已经形成了矩形,一个点可以用他的横纵截距唯一表示。
代码:
#include <bits/stdc++.h> using namespace std; typedef pair<int,int> pii; int n,m; pii red[2005],blue[2005]; pii rred[2005][2],rblue[2005][2]; int vis[2005][2005]; vector<pair<pii,pii> >re,bl; int check1(pair<pii, pii> x, pair<pii, pii> y) { if(y.first.second>=x.first.second&&y.first.second<=x.second.second&& x.first.first>=y.first.first&&x.first.first<=y.second.first) return 1; return 0; } bool check(int t) { int pre=0; re.clear();bl.clear(); for(int i=0;i<n;i++){ rblue[i][0]=make_pair(blue[i].first,blue[i].second-2*t); rblue[i][1]=make_pair(blue[i].first,blue[i].second+2*t); if(i==0)continue; if(blue[i].first==blue[pre].first&&rblue[i][0]<=rblue[pre][1]){ rblue[pre][1]=rblue[i][1]; } else{ bl.push_back(make_pair(rblue[pre][0], rblue[pre][1])); pre=i; } } bl.push_back(make_pair(rblue[pre][0], rblue[pre][1])); pre=0; for(int i=0;i<m;i++){ rred[i][0]=make_pair(red[i].first-2*t,red[i].second); rred[i][1]=make_pair(red[i].first+2*t,red[i].second); if(i==0)continue; if(red[i].second==red[pre].second&&rred[i][0]<=rred[pre][1]){ rred[pre][1]=rred[i][1]; } else{ re.push_back(make_pair(rred[pre][0],rred[pre][1])); pre=i; } } re.push_back(make_pair(rred[pre][0],rred[pre][1])); memset(vis,0,sizeof(vis)); int lenr=re.size(); int lenb=bl.size(); for(int i=0;i<lenb;i++){ for(int j=0;j<lenr;j++){ if(check1(bl[i],re[j])){ for(int k=j+1;k<lenr;k++){ if(check1(bl[i],re[k])){ if(vis[j][k])return true; vis[j][k]++; } } } } } return false; } int main() { scanf("%d%d",&n,&m); for(int i=0;i<n;i++){ int x,y; scanf("%d%d",&x,&y); blue[i]=make_pair(x+y,x-y); } for(int i=0;i<m;i++){ int x,y; scanf("%d%d",&x,&y); red[i]=make_pair(x+y,x-y); } sort(blue,blue+n); for(int i=0;i<m;i++)swap(red[i].first,red[i].second); sort(red,red+m); for(int i=0;i<m;i++)swap(red[i].first,red[i].second); if(blue[0].first==blue[n-1].first||red[0].second==red[m-1].second){ puts("Poor Sereja!"); return 0; } int L=0,R=0x7fffffff,ans=0; while(L<=R){ int mid=(L+R)>>1; if(check(mid)){ R=mid-1; ans=mid; } else L=mid+1; } cout<<ans<<endl; return 0; }