NOIP模拟题 2016.11.8 (2) [线段树] [动态逆序对] [矩阵快速幂] [数论] [欧拉函数]
来源:互联网 发布:在线画板软件 编辑:程序博客网 时间:2024/06/06 04:27
T1:
题意:有一个序列,m次操作,每次操作指定一个位置,将当前位置和该位置后面所有比它小的数构成的子序列排序,放入原位置。求每次操作后,逆序对个数。
首先在线做法不好做,那么考虑离线。
对于一个数,它对逆序对个数贡献为0的时候,就是它之间比它大的数,最早的操作时间。
那么可以采用线段树维护这个最早时间,从前向后走一遍,边走边更新线段树并查询。
每次把这个数对应最早时间的答案减去当前后面比它小的数的个数,也就是当前数对逆序对的贡献。
树状数组求逆序对。。
#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<vector>#include<queue>#include<stack>#include<map>#include<set>#include<string>#include<iomanip>#include<ctime>#include<climits>#include<cctype>#include<algorithm>#ifdef WIN32#define AUTO "%I64d"#else#define AUTO "%lld"#endifusing namespace std;#define smax(x,tmp) x=max((x),(tmp))#define smin(x,tmp) x=min((x),(tmp))#define maxx(x1,x2,x3) max(max(x1,x2),x3)#define minn(x1,x2,x3) min(min(x1,x2),x3)typedef long long LL;const int INF=0x3f3f3f3f;const int maxn = 100005;struct Node{ int val; int dfn;}node[maxn];int n,m;int lim;int a[maxn];inline void init(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&node[i].val),node[i].dfn=INF; for(int i=1;i<=n;i++) a[i] = node[i].val; sort(a+1,a+n+1); lim = unique(a+1,a+n+1) - a - 1; for(int i=1;i<=n;i++) node[i].val = lower_bound(a+1,a+lim+1,node[i].val) - a; for(int i=1;i<=m;i++) { int x; scanf("%d",&x); if(node[x].dfn >= INF) node[x].dfn = i; }}#define lowbit(x) ((x)&(-x))int tree[maxn];inline void add(int x,int val) { for(int i=x;i<=lim;i+=lowbit(i)) tree[i]+=val; }inline int Sum(int x){ int ret = 0; for(int i=x;i;i-=lowbit(i)) ret += tree[i]; return ret;}int MIN[maxn<<2];inline void update(int root) { MIN[root] = min(MIN[root<<1],MIN[root<<1|1]); }int query(int root,int l,int r,int x,int y){ if(x<=l && r<=y) return MIN[root]; int mid = (l+r)>>1; int min1(INF),min2(INF); if(x<=mid && l<=y) min1 = query(root<<1,l,mid,x,y); if(y>=mid+1 && r>=x) min2 = query(root<<1|1,mid+1,r,x,y); return min(min1,min2);}void modify(int root,int l,int r,int pos,int val){ if(l == r) { smin(MIN[root],val); return; } int mid = (l+r)>>1; if(pos<=mid) modify(root<<1,l,mid,pos,val); else modify(root<<1|1,mid+1,r,pos,val); update(root);}LL delta[maxn];int rev[maxn];void work(){ LL ans = 0; for(int i=n;i>=1;i--) { rev[i] = Sum(node[i].val-1); ans += rev[i]; add(node[i].val,1); } memset(MIN,0x3f,sizeof(MIN)); for(int i=1;i<=n;i++) { modify(1,1,lim,node[i].val,node[i].dfn); // update first int T = query(1,1,lim,node[i].val,lim); // query with itself if(T >= INF) continue; delta[T] += rev[i]; // if the same , calculate after modified } printf(AUTO"\n",ans); for(int i=1;i<=m;i++) { ans -= delta[i]; printf(AUTO"\n",ans); }}int main(){ freopen("A.in","r",stdin); freopen("A.out","w",stdout); init(); work(); return 0;}
T2:
题意:一开始有9个机器人分别站在0~8这九个位置上,每个机器人可以上下左右移动,也可以不动,求经过N步后,每个位置恰好有一个机器人的方案数。
很明显是矩阵快速幂。。。
构造转移矩阵通过abs(i%3-j%3) + abs(i/3-j/3) == 1来构造。
注意最后答案的求法,一共有9!种最终排列方式,那么对于每一种方式,用乘法原理得到当前终态的方案数,最后把所有方案数加起来即可。
#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<vector>#include<queue>#include<stack>#include<map>#include<set>#include<string>#include<iomanip>#include<ctime>#include<cctype>#include<algorithm>#ifdef WIN32#define AUTO "%I64d"#else#define AUTO "%lld"#endifusing namespace std;#define smax(x,tmp) x=max((x),(tmp))#define smin(x,tmp) x=min((x),(tmp))#define maxx(x1,x2,x3) max(max(x1,x2),x3)#define minn(x1,x2,x3) min(min(x1,x2),x3)typedef long long LL;template <class T> inline void read(T &x){ x = 0; T flag = 1; char ch = (char)getchar(); while(ch<'0' || ch>'9') { if(ch == '-') flag = -1; ch = (char)getchar(); } while(ch>='0' && ch<='9') { x = (x<<1) + (x<<3) + ch - '0'; ch = (char)getchar(); } x *= flag;}template <class T> T gcd(T a,T b) { return !b?a:gcd(b,a%b); }const int maxn = 10;const int N = 9;const int mod = 1000000007;struct Matrix{ LL w[maxn][maxn]; Matrix() { memset(w,0,sizeof(w)); } Matrix operator * (const Matrix &t) { Matrix ret; for(int i=0;i<N;i++) for(int j=0;j<N;j++) for(int k=0;k<N;k++) (ret.w[i][j] += w[i][k] * t.w[k][j] % mod) %=mod; return ret; } void operator *= (Matrix &t) { (*this) = t * (*this); }};Matrix quick_exp(Matrix tmp,LL p){ Matrix ans; for(int i=0;i<N;i++) ans.w[i][i]=1; while(p) { if(p&1) ans *= tmp; p >>= 1; tmp *= tmp; } return ans;}int a[maxn];int main(){ freopen("B.in","r",stdin); freopen("B.out","w",stdout); LL n; read(n); Matrix delta; for(int i=0;i<N;i++) for(int j=0;j<N;j++) if(abs(i%3-j%3) + abs(i/3-j/3) == 1) delta.w[i][j] = 1; for(int i=0;i<N;i++) delta.w[i][i] = 1; delta = quick_exp(delta,n); for(int i=0;i<N;i++) a[i]=i; LL ans = 0; do { LL tmp = 1; for(int i=0;i<N;i++) (tmp *= delta.w[i][a[i]]) %= mod; (ans += tmp) %=mod; }while(next_permutation(a,a+N)); printf(AUTO,ans); return 0;}
T3:
题意:求gcd(i,j)的k次方的和。
0 0
- NOIP模拟题 2016.11.8 (2) [线段树] [动态逆序对] [矩阵快速幂] [数论] [欧拉函数]
- NOIP模拟题 [线段树][矩阵快速幂]
- NOIP模拟题 2016.11.9 [动态规划] [数论] [二分答案] [启发式合并] [线段树] [树链剖分]
- NOIP模拟题 2016.9.3 [数论] [逆序对] [树状数组] [树形dp]
- NOIP模拟题 2016.11.2 [数论]
- 欧拉函数+矩阵快速幂 Password
- 【Noip模拟】【dp】【LIS】【矩阵快速幂】
- [NOIP模拟][欧拉函数]切蛋糕
- NOIP模拟题 2016.11.14 [动态规划] [线段树优化DP] [字符串的复制粘贴DP]
- NOIP模拟题 [模拟][DP][线段树]
- POJ 3696 : The Luckiest number - 欧拉函数,快速幂[数论好题]
- 统计逆序对--函数式线段树
- 【hdu2462】【数论】【欧拉函数+欧拉定理+大数快速幂】The Luckiest number
- [NOIP基础数论]快速幂
- 【NOIP模拟题】【线段树】2016.11.10第三题题解
- hdu5667 Sequence 【矩阵快速幂+欧拉函数降次】
- HDU 5667 Sequence【矩阵快速幂】【欧拉函数】
- hdu 5667(矩阵快速幂+欧拉函数)
- FFmpeg3.2最新版编译Mediacodec For Android脚本
- CentOS7中启动/停止/重启服务命令
- 微信开发第二天(创建第一个微信小程序)
- C语言程序练习三
- Linux学习之:七种运行级别
- NOIP模拟题 2016.11.8 (2) [线段树] [动态逆序对] [矩阵快速幂] [数论] [欧拉函数]
- 自定义线性滤波器
- 基于websocket写的一个在线联机小游戏:六子冲棋
- 选择排序法
- IIC通信协议
- FFMPEG解码流程理解搜集整理及tutorial5的理解,主要是音视频同步
- Android API Level、sdk版本与发行日期 对照表
- java中父类和子类初始化顺序
- 【嵌入式】STM32的库函数使用