签到5分钟,挂机2小时 然后掉分
想了两个小时B,想着用树状数组维护数量,但实际上他不动态的去更改的话,似乎用个数组,最多再统计一下前缀和,即可实现树状数组的功能,太假了。后来想的set,pair。
总而言之,没把问题想透。
其实对一个序列而言,如果他存在一个递增的子序列,那么所有别的序列+这个序列合成产生的答案都是满足的。所以这些序列对答案的贡献n都是满的。
我们只对另一些序列进行操作,对于那些不存在递增子序列的序列,我们给他标记,并且统计他们最大值出现的次数。(这里我自己写烦了,如官方题解所说,这样的序列最大值肯定是第一个元素,最小值肯定是最后一个元素)
考虑从n*n中减去不满足的答案。
对这些序列的最大值出现次数求一下前缀和
最后遍历对每个不存在递增子序列的序列,减去最大值比当前序列最小值还要<=的个数,最后得出来的就是答案了。
还有对上述序列最大值 排完序用lowerbound的做法,思想也是一样的。
1 #include
2 #ifndef ONLINE_JUDGE3 #define debug(x) cout << #x << ": " << x << endl
4 #else
5 #define debug(x)
6 #endif
7 using namespacestd;8 typedef long longll;9 const int MAXN=1e5+7;10 const int INF=0x3f3f3f3f;11 const int MOD=1e9+7;12
13 intma[MAXN],mi[MAXN];14
15 intn,m;16
17 intarr[MAXN];18
19 int cnt[1100000];20 int flag[110000];21
22 intmain()23 {24 ios::sync_with_stdio(false);25 cin.tie(0);26 cin>>n;27 memset(mi,0x3f,sizeof(mi));28 for(int i=0,l;i>l;31 for(int j=0;j>arr[j];34 if(arr[j]>mi[i]) flag[i]=1;35 ma[i]=max(ma[i],arr[j]);36 mi[i]=min(mi[i],arr[j]);37 }38 if(!flag[i])39 cnt[ma[i]]++;40 }41 ll ans=1ll*n*n;42 for(int i=1;i<=1000000;++i) cnt[i]+=cnt[i-1];43 for(int i=0;i
View Code
有趣的计数题,感觉可以当结论记住。题意就是对n的全排列,统计所有的[l,r]使得区间内的max-min==r-l,统计这样的l,r数量。
显然对于阶乘次数的每个排列去找这样的l,r,不太现实。统计也很困难。
我们不固定fix这个排列,而是固定一个l,r,对于一个长度为len=r-l+1的区间,(选择的是数必然是一个a~a+len-1的一个排列),这区间内的数的排列顺序组合有len!个,将这个区间缩成为一个数,算上剩余的数,就是(n-len+1),也就有(n-len+1)!个。
然后从长度为n的区间中选这样连续长len区间,又有n-len+1个选法,比如说 n=3,选len=2的区间,有两种选法。
然后式子就推出来了,然后对每个len 1~n 统计答案即可。
这也tql8.
写题解希望记住!主要还是思维吧,不从排列突破,从l,r的选取突破。
1 #include
2 #ifndef ONLINE_JUDGE3 #define debug(x) cout << #x << ": " << x << endl
4 #else
5 #define debug(x)
6 #endif
7 using namespacestd;8 typedef long longll;9 const int MAXN=3e5+7;10 const int INF=0x3f3f3f3f;11 const int MOD=1e9+7;12
13 ll fac[MAXN];14 ll n,m;15 intmain()16 {17 ios::sync_with_stdio(false);18 cin.tie(0);19 cin>>n>>m;20 fac[0]=1;21 for(int i=1;i
View Code