D:
定义表G(i,j)=gcd(i,j),给出一段序列,问该序列是否在n*m的G表上的某一行出现过。
首先考虑行,设x为该序列所有数的最小公倍数,那么首先x肯定是可以满足该表的需求的,而更大的x的倍数只可能导致数列中的值变大,所以我们只需要检验行为x是否存在答案即可。
然后考虑列,设序列中的数位z1、z2……,如果我们最后求出来的列为j,那么我们有:
gcd(x,j)=z1
gcd(x,j+1)=z2
……
由这些式子可以得出:
j mod z1=0
j+1 mod z2=0
……
于是变成多个同余方程的问题,中国剩余定理解出最小的j,如果此时不满足那么更大的j也肯定不满足。因为下一个满足的j为j+x,但是j+x后与x的gcd是不会变的,所以只需要检验解出来的最小的j即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<algorithm>
5
6 using namespace std;
7
8 int k;
9
10 long long n,m,z[10010];
11
12 long long gcd(long long a,long long b)
13 {
14 if (!b) return a;
15 else return gcd(b,a%b);
16 }
17
18 int main()
19 {
20 scanf("%I64d%I64d%d",&n,&m,&k);
21 for (int a=1;a<=k;a++)
22 scanf("%I64d",&z[a]);
23 long long v=z[1];
24 for (int a=2;a<=k;a++)
25 if (v>n) break;
26 else v=v/gcd(v,z[a])*z[a];
27 if (v>n)
28 {
29 printf("NO
");
30 return 0;
31 }
32 long long v1=z[1];
33 long long mo1=z[1];
34 if (v1+k-1>m)
35 {
36 printf("NO
");
37 return 0;
38 }
39 for (int a=2;a<=k;a++)
40 {
41 v1%=mo1;
42 long long v2=((-(a-1))%z[a]+z[a])%z[a];
43 long long mo2=z[a];
44 long long cnt=0;
45 if (mo1>mo2)
46 {
47 while (cnt<=mo2 && v1+k-1<=m && v1%mo2!=v2)
48 v1+=mo1,cnt++;
49 }
50 else
51 {
52 while (cnt<=mo1 && v2+k-1<=m && v2%mo1!=v1)
53 v2+=mo2,cnt++;
54 v1=v2;
55 }
56 v2%=mo2;
57 if (v1%mo2!=v2 || v1+k-1>m)
58 {
59 printf("NO
");
60 return 0;
61 }
62 mo1=mo1/gcd(mo1,mo2)*mo2;
63 }
64 if (!v1) v1=mo1;
65 for (long long a=1;a<=k;a++)
66 if (gcd(v1+a-1,v)!=z[a])
67 {
68 printf("NO
");
69 return 0;
70 }
71 printf("YES
");
72
73 return 0;
74 }
E:
给出序列a和b,长度分别为l1和l2,问在a序列中的l1-l2+1长度为l2的序列中,有多少个能和b中的数找到一种配对方式使得配对的数加起来都大于每个给定的数。
我们将b排序,那么我们假设要新加入一个配对的数,和它可以配对的数在b中所对应的区间时[x,l2],那么不合法的情况是可能是某一段后缀的个数已经小于了必须在这一段中配对的数的个数,所以用线段树维护后缀和即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<algorithm>
5
6 using namespace std;
7
8 #define wmt 1,m+1,1
9 #define lson l,m,rt<<1
10 #define rson m+1,r,rt<<1|1
11
12 const int maxn=150010;
13
14 int n,m,h,z[maxn],y[maxn<<2|1],x[maxn<<2|1],p[maxn];
15
16 void update(int rt)
17 {
18 y[rt]=min(y[rt<<1],y[rt<<1|1]);
19 }
20
21 void push_x(int rt)
22 {
23 if (x[rt])
24 {
25 y[rt<<1]+=x[rt];x[rt<<1]+=x[rt];
26 y[rt<<1|1]+=x[rt];x[rt<<1|1]+=x[rt];
27 x[rt]=0;
28 }
29 }
30
31 void build(int l,int r,int rt)
32 {
33 if (l==r)
34 {
35 y[rt]=m-l+1;
36 return;
37 }
38 int m=(l+r)>>1;
39 build(lson);
40 build(rson);
41 update(rt);
42 }
43
44 void modify(int l,int r,int rt,int nowl,int nowr,int delta)
45 {
46 if (nowl<=l && r<=nowr)
47 {
48 x[rt]+=delta;
49 y[rt]+=delta;
50 return;
51 }
52 push_x(rt);
53 int m=(l+r)>>1;
54 if (nowl<=m) modify(lson,nowl,nowr,delta);
55 if (m<nowr) modify(rson,nowl,nowr,delta);
56 update(rt);
57 }
58
59 int main()
60 {
61 scanf("%d%d%d",&n,&m,&h);
62 for (int a=1;a<=m;a++)
63 scanf("%d",&z[a]);
64 sort(z+1,z+m+1);
65 for (int a=1;a<=n;a++)
66 {
67 int v;
68 scanf("%d",&v);
69 int l=0,r=m;
70 while (l+1!=r)
71 {
72 int m=(l+r)>>1;
73 if (z[m]+v>=h) r=m;
74 else l=m;
75 }
76 if (v+z[r]<h) r++;
77 p[a]=r;
78 }
79 build(wmt);
80 for (int a=1;a<m;a++)
81 modify(wmt,1,p[a],-1);
82 int ans=0;
83 for (int a=m;a<=n;a++)
84 {
85 modify(wmt,1,p[a],-1);
86 ans+=(y[1]==0);
87 modify(wmt,1,p[a-m+1],1);
88 }
89 printf("%d
",ans);
90
91 return 0;
92 }