【NOIP2012】提高组
Day1
T1vigenere密码
vijos截得不全导致题意可能会理解错,注意小写字母应该是先转大写进行变换,再根据情况看是否需要再转成小写。
然后,然后就没了啊。
1 #include<cstdio> 2 #include<cstring> 3 char ch[105],tt[1005],an[1005]; 4 int len,le,mi[105]; 5 int main(){ 6 scanf("%s %s",ch+1,tt+1); 7 len=strlen(ch+1);le=strlen(tt+1); 8 for(int i=1;i<=len;i++){ 9 if(ch[i]>='a')ch[i]=ch[i]-('a'-'A'); 10 mi[i]=ch[i]-130; 11 } 12 int h=1; 13 for(int i=1;i<=le;i++,h++){ 14 if(h>len)h=1; 15 int p=tt[i]>='a'?tt[i]-('a'-'A'):tt[i]; 16 p-=65; 17 for(int x='A';x<='Z';x++)if((x+mi[h])%26==p){an[i]=x;break;} 18 if(tt[i]>='a')an[i]+='a'-'A'; 19 } 20 for(int i=1;i<=le;i++)printf("%c",an[i]); 21 return 0; 22 }
T2国王游戏
对于两个人的顺序安排,不会对前后的其他人造成影响。
设两个人左右手上数字分别为l1,r1;l2,r2。
那么答案就是min(max(l1/r2,1/r1),max(l2/r1,1/r2))。-->忽略前面的数,反正也会被约掉
1.当r1>r2时:
l1/r2>1/r1;l1/r2>1/r2;
所以答案是min(l1/r2,l2/r1)。
2.当r2>r1时:
l2/r1>1/r2;l2/r1>1/r1;
所以答案tm还是min(l1/r2,l2/r1)。
综上答案只跟l1/r2和l2/r1的大小的关系有关。
交叉相乘得:
当l1*r1>l2*r2时,l1/r2>l2/r1;否则l1/r2<l2/r1。
那么只要按l*r从小到大排个序就好啦。
对了好像还有个高精乘低精和高精除低精......
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<queue> 5 #include<cmath> 6 typedef long long LL; 7 const int N=1005; 8 int read(){ 9 int ans=0,f=1;char c=getchar(); 10 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 11 while(c>='0'&&c<='9'){ans=ans*10+c-48;c=getchar();} 12 return ans*f; 13 } 14 struct node{ 15 LL li,ri,wi; 16 bool operator <(const node&p)const{return p.wi<wi;} 17 }; 18 std::priority_queue<node>q; 19 LL mxa[5000],ch[5000],y[5000]; 20 void mul(LL x[],LL d){ 21 LL jin=0,wei=log(d)/log(10)+1; 22 x[0]+=wei; 23 for(int i=1;i<=x[0];i++){ 24 x[i]=x[i]*d+jin; 25 jin=x[i]/10; 26 x[i]%=10; 27 } 28 while(x[x[0]]==0)x[0]--; 29 } 30 void mol(LL x[],LL d){ 31 LL sh=0; 32 for(int i=x[0];i>=1;i--){ 33 sh=sh*10+x[i]; 34 x[i]=sh/d; 35 sh=sh%d; 36 } 37 while(x[x[0]]==0)x[0]--; 38 } 39 void max(){ 40 if(y[0]<mxa[0])return; 41 if(mxa[0]<y[0]){memcpy(mxa,y,sizeof(mxa));return;} 42 for(int i=mxa[0];i>=1;i--) 43 if(y[i]>mxa[i]){memcpy(mxa,y,sizeof(mxa));return;} 44 } 45 int main(){ 46 int n=read(); 47 LL op=read();read(); 48 while(op)ch[++ch[0]]=op%10,op/=10; 49 for(int i=1,a,b;i<=n;i++){ 50 a=read();b=read(); 51 q.push((node){a,b,a*b}); 52 } 53 for(int i=1;i<=n;i++){ 54 node p=q.top();q.pop(); 55 for(int i=0;i<=ch[0];i++)y[i]=ch[i]; 56 mol(y,p.ri); 57 max(); 58 mul(ch,p.li); 59 } 60 for(int i=mxa[0];i>=1;i--)printf("%lld",mxa[i]); 61 return 0; 62 }
T3开车旅行
从后往前预处理出离每个点的最近、次近距离(平衡树),那么第一第二问就都是一个倍增可以解决的东西了。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<set> 5 #define mem(a,p) memset(a,p,sizeof(a)) 6 typedef long long LL; 7 const int N=1e5+10; 8 struct node{ 9 int hi,id; 10 bool operator <(const node&p)const{return p.hi>hi;} 11 }; 12 struct no{int hi,yu,id;}; 13 bool cmp(no a,no b){return a.hi!=b.hi?a.hi<b.hi:a.yu<b.yu;} 14 int n,h[N],m; 15 typedef std::multiset<node>myset; 16 typedef myset::iterator IT; 17 myset se; 18 LL ato[N][22],bto[N][22]; 19 int g[N][22],to[N],co[N]; 20 int read(){ 21 int ans=0,f=1;char c=getchar(); 22 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 23 while(c>='0'&&c<='9'){ans=ans*10+c-48;c=getchar();} 24 return ans*f; 25 } 26 int main(){ 27 n=read(); 28 for(int i=1;i<=n;i++)h[i]=read(); 29 se.insert((node){h[n],n});se.insert((node){h[n-1],n-1}); 30 bto[n-1][0]=abs(h[n]-h[n-1]);to[n-1]=n; 31 for(int i=0;i<=n;i++) 32 for(int j=0;j<=20;j++)ato[i][j]=bto[i][j]=2e9; 33 for(int i=n-2;i>=1;i--){ 34 IT it=se.lower_bound((node){h[i],i}); 35 IT it0=it; 36 no q[5];int tot=0; 37 if(it!=se.end()){ 38 q[++tot]=(no){abs(it->hi-h[i]),it->hi,it->id}; 39 it++; 40 if(it!=se.end())q[++tot]=(no){abs(it->hi-h[i]),it->hi,it->id}; 41 } 42 if(it0!=se.begin()){ 43 it0--;q[++tot]=(no){abs(h[i]-it0->hi),it0->hi,it0->id}; 44 if(it0!=se.begin())it0--,q[++tot]=(no){abs(h[i]-it0->hi),it0->hi,it0->id}; 45 } 46 se.insert((node){h[i],i}); 47 if(tot<=1)continue; 48 std::sort(q+1,q+1+tot,cmp); 49 ato[i][0]=q[2].hi;to[i]=q[1].id;g[i][0]=q[2].id;co[i]=q[2].id; 50 if(to[q[2].id])bto[i][0]=abs(h[to[q[2].id]]-h[q[2].id]),g[i][0]=to[q[2].id]; 51 } 52 for(int i=n;i>=1;i--){ 53 for(int j=1;i+(1<<j)<=n;j++){ 54 g[i][j]=g[g[i][j-1]][j-1]; 55 ato[i][j]=ato[i][j-1]+ato[g[i][j-1]][j-1]; 56 bto[i][j]=bto[i][j-1]+bto[g[i][j-1]][j-1]; 57 } 58 } 59 int x0=read();double mni=2e9;int id=0; 60 for(int i=1;i<=n;i++){ 61 LL sa=0,sb=0;int i0=i,xx=x0; 62 bool fl=0; 63 for(int j=20;j>=0;j--){ 64 if((ato[i][j]+bto[i][j]>xx&&j)||(!j&&ato[i][j]>xx))continue; 65 sa+=ato[i][j]; 66 xx-=ato[i][j]; 67 if(bto[i][j]>xx){fl=1;break;} 68 sb+=bto[i][j];xx-=bto[i][j]; 69 i=g[i][j]; 70 } 71 if(!fl&&ato[i][0]<=xx)sa+=ato[i][0],i=co[i]; 72 i=i0; 73 if(sb==0)continue; 74 if(mni==sa*1.0/sb&&h[id]<h[i])id=i; 75 else if(mni>sa*1.0/sb)mni=sa*1.0/sb,id=i; 76 } 77 printf("%d\n",id);m=read(); 78 for(int i=1;i<=m;i++){ 79 LL si=read(),xi=read(); 80 LL sa=0,sb=0;int fl=0; 81 for(int j=20;j>=0;j--) 82 if((j&&ato[si][j]+bto[si][j]<=xi)||(!j&&ato[si][0]<=xi)){ 83 sa+=ato[si][j];xi-=ato[si][j]; 84 if(bto[si][j]>xi){fl=1;break;} 85 xi-=bto[si][j];sb+=bto[si][j]; 86 si=g[si][j]; 87 } 88 if(!fl&&ato[si][0]<=xi)sa+=ato[si][0],si=co[si]; 89 printf("%lld %lld\n",sa,sb); 90 } 91 return 0; 92 }
Day2
T1同余方程
以前的博客->戳这里
T2借教室
二分第一个出现冲突的点,然后就差分前缀和判si[i]是否大于d[i]即可。复杂度O(nlog(n))。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 const int N=1e6+5; 5 int read(){ 6 int ans=0,f=1;char c=getchar(); 7 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 8 while(c>='0'&&c<='9'){ans=ans*10+c-48;c=getchar();} 9 return ans*f; 10 } 11 int n,m; 12 int di[N],dj[N],si[N],sj[N]; 13 int tr[N]; 14 bool check(int x){ 15 memset(tr,0,sizeof(tr)); 16 for(int i=1;i<=x;i++){ 17 tr[si[i]]+=dj[i];tr[sj[i]+1]-=dj[i]; 18 } 19 int sum=0; 20 for(int i=1;i<=n;i++){ 21 sum+=tr[i]; 22 if(sum>di[i])return 0; 23 } 24 return 1; 25 } 26 int main(){ 27 n=read();m=read(); 28 for(int i=1;i<=n;i++)di[i]=read(); 29 for(int i=1;i<=m;i++){ 30 dj[i]=read();si[i]=read();sj[i]=read(); 31 } 32 int l=0,r=m+1; 33 while(l<r-1){ 34 int mid=(l+r)>>1; 35 if(check(mid))l=mid; 36 else r=mid; 37 } 38 if(l==m)printf("0"); 39 else printf("-1\n%d",l+1); 40 return 0; 41 }
T3疫情控制
挺难的一道题,然而我之前一个错的很离谱的贪心居然能过vijos上的全部数据......建议写完也去洛谷那边交一下......
不合法无非就是军队数小于根节点的孩子数,没什么难度。
二分一个时间,然后对于每支军队都尽量往上走。
能走到根节点的军队入队,按照剩余可用时间从小到大排序;到不了的就停在最多能走到的点打个标记就行。
dfs根的每棵子树,记一下当前子树是否还有叶子没被控制,有的话记录一下这棵子树里能走到根的最深点-->last(因为它最没用),然后根的次子节点入队。
将子节点构成的队按距离从小到大排序。
枚举每支军队,如果它原来属于子树还没被覆盖,就让它回到它原来的子树去,否则就把离根最近的子节点分配给它,当然到达不了就算了。
判合法就很明显了吧......
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define mem(a,p) memset(a,p,sizeof(a)) 5 typedef long long LL; 6 const int N=5e4+7; 7 using std::sort; 8 int n,m,first[N],tot=0,si[N],son[N],op; 9 int gr[N][22],deep[N]; 10 LL dis[N][22],tofa[N]; 11 struct node{int ne,to;LL w;}e[N*2]; 12 struct no{LL w;int id;}q[N],st[N]; 13 bool cmp(no a,no b){return a.w<b.w;} 14 int read(){ 15 int ans=0,f=1;char c=getchar(); 16 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 17 while(c>='0'&&c<='9'){ans=ans*10+c-48;c=getchar();} 18 return ans*f; 19 } 20 void ins(int u,int v,int w){ 21 e[++tot]=(node){first[u],v,w};first[u]=tot; 22 } 23 void dfs(int x,int fa){ 24 for(int i=1;(1<<i)<=deep[x];i++){ 25 gr[x][i]=gr[gr[x][i-1]][i-1]; 26 dis[x][i]=dis[x][i-1]+dis[gr[x][i-1]][i-1]; 27 } 28 for(int i=first[x];i;i=e[i].ne){ 29 int to=e[i].to; 30 if(to==fa)continue; 31 gr[to][0]=x;dis[to][0]=e[i].w; 32 deep[to]=deep[x]+1; 33 tofa[to]=tofa[x]+e[i].w; 34 son[x]++; 35 dfs(to,x); 36 } 37 } 38 bool ok[N],flag[N]; 39 int last; 40 void work(int x,int fa,bool&le,bool p){ 41 for(int i=first[x];i;i=e[i].ne){ 42 int to=e[i].to; 43 if(to==fa)continue; 44 int pp=flag[to]; 45 work(to,x,le,pp|p); 46 } 47 if(!p&&son[x]==0)le=1; 48 if(ok[x]&&tofa[last]<tofa[x])last=x; 49 } 50 int kk[N]; 51 bool vis[N]; 52 bool check(LL x){ 53 int sum=0;op=0;mem(ok,0);mem(flag,0);mem(kk,0);mem(vis,0); 54 for(int i=1;i<=m;i++){ 55 LL x0=x;int id=si[i]; 56 if(tofa[si[i]]<=x){ 57 q[++sum]=(no){x-tofa[si[i]],si[i]};ok[si[i]]=1; 58 continue; 59 } 60 for(int j=20;j>=0;j--){ 61 if((1<<j)>deep[id]||dis[id][j]>x0)continue; 62 x0-=dis[id][j];id=gr[id][j]; 63 } 64 flag[id]=1; 65 } 66 for(int i=first[1];i;i=e[i].ne){ 67 last=0; 68 if(flag[e[i].to])continue; 69 bool pp=!son[e[i].to]; 70 work(e[i].to,1,pp,0); 71 if(!last&&ok[e[i].to])last=e[i].to; 72 kk[last]=e[i].to; 73 if(pp)st[++op]=(no){tofa[e[i].to],e[i].to}; 74 else vis[e[i].to]=1; 75 } 76 vis[0]=1; 77 sort(q+1,q+1+sum,cmp);sort(st+1,st+1+op,cmp);int head=1; 78 for(int i=1;i<=sum;i++){ 79 while(vis[st[head].id]&&head<=op)head++; 80 if(!vis[kk[q[i].id]]&&tofa[kk[q[i].id]]>=st[head].w){ 81 vis[kk[q[i].id]]=1; 82 continue; 83 } 84 if(st[head].w>q[i].w)continue; 85 head++;if(head>op)break; 86 } 87 while(vis[st[head].id]&&head<=op)head++; 88 if(head<=op)return 0; 89 return 1; 90 } 91 int main(){ 92 n=read(); 93 for(int i=1,a,b,c;i<n;i++){ 94 a=read();b=read();c=read(); 95 ins(a,b,c);ins(b,a,c); 96 } 97 dfs(1,0); 98 m=read(); 99 for(int i=1;i<=m;i++)si[i]=read(); 100 if(son[1]>m)return printf("-1"),0; 101 LL l=0,r=1e13; 102 while(l<r){ 103 LL mid=(l+r)>>1; 104 if(check(mid))r=mid; 105 else l=mid+1; 106 } 107 printf("%lld",l); 108 return 0; 109 }