Codeforces #278
来源:互联网 发布:淘宝怎么做定制玻璃 编辑:程序博客网 时间:2024/06/03 21:05
D. 给一个数组,求最少把这个数组分成多少部分,要求每一部分都大于等于l,且最大值和最小值的差不大于s。
显然是dp的思想,大概就是dp[i]=min{dp[k]}+1(j<=k<=i-l),j表示最远从哪个数开始到第i个数满足j到i中最大值和最小值的差不大于s,这个j可以用单调队列解决,开两个单调队列,一个维护区间最大一个维护区间最小。知道j之后,就要从j到i-l之间找到一个dp最小的值,用线段树可以搞。
代码:
#include <stdio.h>#include <string.h>#include <algorithm>using namespace std;#define N 100005#define INF 99999999struct Tree{ int l,r,val;};Tree tree[N*5];int incQueue[N],incHead,incTail;int decQueue[N],decHead,decTail;int dpQueue[N],dpHead,dpTail;int a[100005];int dp[100005];void build(int t,int l,int r){ tree[t].l=l; tree[t].r=r; tree[t].val=INF; if (l==r) return; int mid=(l+r)/2; build(2*t+1,l,mid); build(2*t+2,mid+1,r);}void add(int t,int idx,int val){ if (tree[t].l==tree[t].r) { tree[t].val=val; return; } int mid=(tree[t].l+tree[t].r)/2; if (idx<=mid) add(2*t+1,idx,val); else add(2*t+2,idx,val); tree[t].val=min(tree[2*t+1].val,tree[2*t+2].val);}int query(int t,int l,int r){ if (tree[t].l==l && tree[t].r==r) { return tree[t].val; } int mid=(tree[t].l+tree[t].r)/2; int ret=INF; if (l<=mid) ret=min(ret,query(2*t+1,l,min(mid,r))); if (r>mid) ret=min(ret,query(2*t+2,max(l,mid+1),r)); return ret;}void pushInc(int idx){ while(1) { if (incTail==incHead) break; if (a[incQueue[incTail-1]]<=a[idx]) break; incTail--; } incQueue[incTail++]=idx;}void pushDec(int idx){ while(1) { if (decTail==decHead) break; if (a[decQueue[decTail-1]]>=a[idx]) break; decTail--; } decQueue[decTail++]=idx;}int main(){ int i,j,n,s,l; scanf("%d%d%d",&n,&s,&l); for (i=0;i<n;i++) { scanf("%d",&a[i]); } incHead=incTail=decHead=decTail=dpHead=dpTail=0; build(0,0,n-1); int far=0; for (i=0;i<n;i++) { pushInc(i); pushDec(i); while(1) { if (a[i]-a[incQueue[incHead]]>s) { far=max(far,incQueue[incHead]+1); incHead++; } else break; } while(1) { if (a[decQueue[decHead]]-a[i]>s) { far=max(far,decQueue[decHead]+1); decHead++; } else break; } if (i-far+1<l) dp[i]=-1; else { // printf("%d:%d!\n",i,far); if (far==0) { dp[i]=1; add(0,i,dp[i]); } else { int tmp=query(0,far-1,i-l); // printf("%d: %d~%d %d\n",i,far-1,i-l,tmp); if (tmp==INF) dp[i]=-1; else { dp[i]=tmp+1; add(0,i,dp[i]); } } } } // for (i=0;i<n;i++) printf("%d ",query(0,i,i)); // printf("\n"); if (dp[n-1]==INF) printf("-1\n"); else printf("%d\n",dp[n-1]); return 0;}
只有质数和1和4有解,因为对于合数N可以有N=p1*p2,而p1和p2可以分别从小于N的数当中凑得,因此无论怎么排都会有大于1个取模的结果为0。
4有解是因为4=2*2,而1~3当中只有一个2因子,所以可能会存在解,事实证明也是有解的(1, 3, 2, 4)
因为想要让这个全排列的前i个数相乘模n的结果都不一样,因此n要放在最后一位(不然乘以n之后无论怎么乘 模都是0),1要放在第一位(乘以1之后模不变)。
之后当然看看可不可以构造一个序列使得:
A1%n=1
A1*A2%n=2
A1*A2*A3%n=3
...
A1*A2*...*A_(n-1)%n=n-1
A1*A2*...*An%n=0
且A1=1, An=n。
如果这种构造方法成立,就要证明不存在某个数p(1<p<N),使得ip%n=i+1且jp%n=j+1,根据这两个式子可得:
(i+1+xn)/i=(j+1+yn)/j =>
j+xnj=i+yni =>
i-j=n(xj-yi)
因为i和j都在0和n之间,因此i-j会小于n,但是右边xj-yi是整数,所以唯一满足上述式子的情况就是左边等于右边等于0,即i==j。
所以就证明了不存在某个数p,使得ip%n=i+1且jp%n=j+1。
也就是说这种构造方法是满足A1到An互不相等的。
接下来需要考虑怎么快速的得到p,使得(i-1)*p mod n = i。
考虑费马小定理:a^(n-1) mod n = 1
因此,我们可以让p等于(i-1)^(n-2) * i
这样(i-1)*p= (i-1) * (i-1)^(n-2) * i = (i-1)^(n-1)*i
这样(i-1)^(n-1) mod n=1,所以(i-1)^(n-1)*i mod n = i,即(i-1) * (i-1)^(n-2)*i mod n = i
所以每次只需要快速幂求出这个p,打印输出即可。
代码很简单
#include <stdio.h>#include <math.h>#include <algorithm>using namespace std;bool is_prime(int t){ for (int i=2;i<=sqrt(t*1.0);i++) { if (t%i==0) return false; } return true;}long long f_pow(long long x,int n,int mod){ long long ret=1; while(n) { if (n&1) ret=ret*x%mod; n>>=1; x=x*x%mod; } return ret;}int main(){ int i,j,n; scanf("%d",&n); if (!is_prime(n) && n!=1 && n!=4) { printf("NO\n"); return 0; } printf("YES\n"); if (n==1) { printf("1\n"); return 0; } if (n==4) { printf("1\n3\n2\n4\n"); return 0; } printf("1\n"); for (i=2;i<n;i++) { printf("%d\n",f_pow(i-1,n-2,n)*i%n); } printf("%d\n",n); return 0;}
- Codeforces #278
- 【codeforces】Codeforces Round #278 (Div. 1) 题解
- 【索引】Codeforces Round #278
- CodeForces 278BNew Problem
- CodeForces 278ACircle Line
- Codeforces 278B
- Codeforces 278B Books
- codeforces~~~
- Codeforces
- codeforces
- Codeforces
- codeforces
- codeforces
- Codeforces
- Codeforces
- CodeForces
- CodeForces
- CodeForces
- Rich feature hierarchies for accurate object detection and semantic segmentation(泛读)
- 搬运工的项目总结-1 吐槽篇
- Atitit.web 视频播放器classid clsid 大总结quicktime,vlc 1. Classid的用处。用来指定播放器1 2. <object> 标签用于包含对象,比如图像、音
- Atitit.多媒体区----web视频格式的选择总结
- C语言基础之预处理指令
- Codeforces #278
- Balon白话MSDN:从普通DLL中导出C++类(1) – dllexport和dllimport的使用方法(中英对照、附注解)
- Android之NDK
- 获取vector中出现次数最多的元素
- 文件断点续传原理与实现
- 分割字符串
- Linux系统引导修复
- Codeforces11D(状压dp)
- python 学习笔记之一开发环境搭建