noip2013 提高组
T1 转圈游戏 题目传送门
果不其然 第一题还是模拟题 一波快速幂解决问题
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int read(){ int ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } int n,m,k,x; int qmod(int a,int b,int c){ int ans=1; while(b){ if(b&1) ans=ans*a%c; b=b/2; a=a*a%c; } return ans; } int main() { n=read(); m=read(); k=read(); x=read(); int v=qmod(10,k,n); printf("%d\n",(v*m+x)%n); return 0; }
T2 火柴排队 题目传送门
这是道树状数组求逆序数对的题目 当然还要加一波离散化就好了 不过这题的离散化很玄学哇 2333
#include<cstdio> #include<cstring> #include<algorithm> #define LL long long using namespace std; const int M=100007,mod=99999997; int read(){ int ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } struct node{int w,pos;}a[M],b[M]; bool cmp(node a,node b){return a.w<b.w;} int c[M],sum[M],n; LL ans; int lowbit(int x){return x&-x;} void insert(int x){ while(x<=n){ sum[x]++; x+=lowbit(x); } } int push_sum(int x){ int ans=0; while(x){ans+=sum[x]; x-=lowbit(x);} return ans; } int main() { n=read(); for(int i=1;i<=n;i++) a[i].w=read(),a[i].pos=i; for(int i=1;i<=n;i++) b[i].w=read(),b[i].pos=i; sort(a+1,a+1+n,cmp); sort(b+1,b+1+n,cmp); for(int i=1;i<=n;i++) c[a[i].pos]=b[i].pos; for(int i=1;i<=n;i++){ insert(c[i]); ans=(ans+i-push_sum(c[i]))%mod; } printf("%lld\n",ans); return 0; }
T3 货车运输 题目传送门
几乎是裸的lca吧 用lca维护一波最近公共祖先和路径最小值就好了
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int M=150007; int read(){ int ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } int w[M],n,f[M][2]; int main() { n=read(); for(int i=1;i<=n;i++) w[i]=read(),f[i][0]=f[i][1]=1; for(int i=1;i<=n;i++) for(int j=i-1;j;j--){ if(w[i]>w[j]) f[i][1]=max(f[i][1],f[j][0]+1); if(w[j]>w[i]) f[i][0]=max(f[i][0],f[j][1]+1); if(f[i][0]!=1&&f[i][1]!=1) break; } printf("%d\n",max(f[n][0],f[n][1])); return 0; }
T4 积木大赛 题目传送门
这道题就是我们只考虑相邻两列h1 h2 容易证明他的无后效性
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int M=150007; int read(){ int ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } int w[M],n,f[M][2]; int main() { n=read(); for(int i=1;i<=n;i++) w[i]=read(),f[i][0]=f[i][1]=1; for(int i=1;i<=n;i++) for(int j=i-1;j;j--){ if(w[i]>w[j]) f[i][1]=max(f[i][1],f[j][0]+1); if(w[j]>w[i]) f[i][0]=max(f[i][0],f[j][1]+1); if(f[i][0]!=1&&f[i][1]!=1) break; } printf("%d\n",max(f[n][0],f[n][1])); return 0; }
当然其实正解我也写了一波 比dp快很多呀 2333
至于为什么是拐点
这道题就是求一个 大小大小大小或者 小大小大小大 的序列 其中大小是相对于相邻两个数而言
我们可以分情况考虑答案
1. 前一个数是 ‘大’ (定义为last)那么我们下一个数一定要比他小 这时我们考虑当前数 (定义为now)
如果now<last 很明显符合 那么答案++
如果last>=now 那么前面小于last的以及后面能<last的同样能符合now 那么我们完全可以用now代替last
2 前一个数是 ‘下' 同1
所以这个问题就转换成了求拐点数 拐点数+1就是答案了 2333
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int M=100007; int read(){ int ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } int n,v[M]; int f,last,ans; void solve(){ int sum=1; for(int i=2;i<=n;i++){ if(f==1&&v[i]<last) f=-1,sum++; if(f==-1&&v[i]>last) f=1,sum++; last=v[i]; } ans=max(ans,sum); } int main() { n=read(); for(int i=1;i<=n;i++) v[i]=read(); last=v[1]; f=1; solve(); last=v[1]; f=-1; solve(); printf("%d\n",ans); return 0; }
T5 花匠 题目传送门
正解似乎是算拐点+1 数据随机dp水过
0表示他是作为比较小的那个点 1则相反
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int M=150007; int read(){ int ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } int w[M],n,f[M][2]; int main() { n=read(); for(int i=1;i<=n;i++) w[i]=read(),f[i][0]=f[i][1]=1; for(int i=1;i<=n;i++) for(int j=i-1;j;j--){ if(w[i]>w[j]) f[i][1]=max(f[i][1],f[j][0]+1); if(w[j]>w[i]) f[i][0]=max(f[i][0],f[j][1]+1); if(f[i][0]!=1&&f[i][1]!=1) break; } printf("%d\n",max(f[n][0],f[n][1])); return 0; }
T6 华容道 题目传送门
这道题黄学长都弃坑了 我纠结什么呢 以后补吧 hzwer