T1:
注意下面的那个求平均值的公式少了一个除大小,自行补上。
这种数据范围的最小方差生成树?真的可做?
BZOJ3754那题我可是n^2k暴力卡过去的啊......(好像只能暴力QAQ)
正解?标算好像就是求尽可能近的区间生成树。显然不对啊......
不可做,不可做。咕咕咕了。
T2:
怎么又是原题?
真不是BZOJ3505吗?
考虑枚举所有选三个点的方案再减去三点共线的。
就是C(n*m,3)-m*C(n,3)-n*C(m,3)-2*sigma(i from 1 to n-1,j from 1 to m-1)(gcd(i,j)-1)(n-i)(m-j)。
也就是全部的方案数为C(n*m,3),平行于坐标轴三点共线的有m*C(n,3)-n*C(m,3)种,斜向三点共线的,考虑枚举两边的两个点形成的向量,这样的向量存在(n-i)(m-j)个,对于每个向量,把中间点放置在格点上的方案有gcd(i,j)-1种,因为左右两种方向所以要全部*2。
但是,数据范围什么鬼......
考虑对公式进行数学变形:
右边的东西就很容易求和了(具体数学告诉你这样交换求和变量是对的):
对于gcd反演的惯例反演就是变成phi啦(什么这步你推不出来?丢人!退役吧!):
(不要吐槽我的公式渲染,msword2016在linux下就是这个德行)
由于求和式子的取值至于(n-1)/t和(m-1)/t有关,数论分块就很显然了。
然而卡常只有90分......
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define debug cout 6 typedef long long int lli; 7 using namespace std; 8 const int maxn=3e6+1e2,lim=3e6; 9 const int mod=1e9+7,inv[]={0,1,500000004,333333336}; 10 11 inline lli C3(lli x) { 12 lli ret = 1; x %= mod; 13 for(int i=0;i<3;i++) ret = ret * ( x - i + mod ) % mod , ret = ret * inv[i+1] % mod; 14 return ret; 15 } 16 inline lli LSU(lli x) { 17 return x * ( x + 1 ) % mod * inv[2] % mod; 18 } 19 20 lli phi[maxn],phix[maxn],phixx[maxn]; 21 int n,m; 22 23 inline void sieve() { 24 static int prime[maxn],cnt; 25 static bool vis[maxn]; 26 phi[1] = 1; 27 for(int i=2;i<=lim;i++) { 28 if( !vis[i] ) prime[++cnt] = i , phi[i] = i - 1; 29 for(int j=1;j<=cnt&&(lli)i*prime[j]<=lim;j++) { 30 const int tar = i * prime[j]; 31 vis[tar] = 1; 32 if( i % prime[j] ) phi[tar] = phi[i] * ( prime[j] - 1 ); 33 else { phi[tar] = phi[i] * prime[j]; break; } 34 } 35 } 36 for(int i=1;i<=lim;i++) { 37 phix[i] = phi[i] * i % mod , phixx[i] = phix[i] * i % mod; 38 phi[i] = ( phi[i] + phi[i-1] ) % mod , phix[i] = ( phix[i] + phix[i-1] ) % mod , phixx[i] = ( phixx[i] + phixx[i-1] ) % mod; 39 }; 40 } 41 42 inline lli initans() { 43 lli ret = ( ( C3((lli)n*m) - n * C3(m) - m * C3(n) ) % mod + mod ) % mod; 44 ret = ( ret + LSU(n-1) * LSU(m-1) % mod * 2 % mod ) % mod; 45 return ret; 46 } 47 inline lli getsub() { // assert n <= m . 48 lli ret = 0; 49 if( n > m ) swap(n,m); 50 for(int i=1,j;i<n;i=j+1) { 51 j = min( ( n - 1 ) / ( ( n - 1 ) / i ) , ( m - 1 ) / ( ( m - 1 ) / i ) ); 52 const lli apn = ( n - 1 ) / i , apm = ( m - 1 ) / i; 53 ret += ( phi[j] - phi[i-1] + mod ) % mod * apn % mod * apm % mod * n % mod * m % mod , ret %= mod; 54 ret += ( phixx[j] - phixx[i-1] + mod ) % mod * LSU(apn) % mod * LSU(apm) % mod , ret %= mod; 55 ret -= ( phix[j] - phix[i-1] + mod ) % mod * LSU(apn) % mod * apm % mod * m % mod , ret = ( ret + mod ) % mod; 56 ret -= ( phix[j] - phix[i-1] + mod ) % mod * LSU(apm) % mod * apn % mod * n % mod , ret = ( ret + mod ) % mod; 57 } 58 ret = ret * 2 % mod; 59 return ret; 60 } 61 62 int main() { 63 sieve(); 64 while( scanf("%d%d",&n,&m) == 2 && ( n || m ) ) n++ , m++ , printf("%lld ",(initans()-getsub()+mod)%mod); 65 }
T3:
这题什么东西啊?真的可做?
写了一个三分套(线段树+RMQ+三分套二分)(什么鬼),发现不符合单调性,就能过样例,对拍拍一组WA一组。
无奈写了个O(n^2logn)的暴力,放进去交了,骗了20分......
正解是这个样子的:
(表示您并没有告诉我数据随机)
但是,如果数据真的随机,并没有那么麻烦!
我可以写一个O(n^2)暴力,从右向左枚举左端点,然后从左向右枚举右端点,对于每个右端点,我么令sj表示当前左端点到j的区间的最小和。显然每次更新的时候sj=min(sj,sj-1,ai-aj),于是就去掉log了。
这样暴力显然不能AC,我们能加入剪枝,如果当前sj*(n-i)已经<=答案了,我们就可以把内层循环break掉了。
然后就能AC啦!
考场20分代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<set> 6 #define debug cout 7 typedef long long int lli; 8 using namespace std; 9 const int maxn=1e5+1e2,lim=1e5; 10 const int inf=0x3f3f3f3f , minf = -inf; 11 const lli lli_inf = 0x3f3f3f3f3f3f3f3fll; 12 13 int in[maxn],n,k; 14 15 namespace Force { 16 const int maxn=2e3+1e2; 17 int f[maxn][maxn]; 18 multiset<int> ms; 19 inline void work() { 20 lli ans = -lli_inf; 21 for(int i=1;i<=n;i++) { 22 ms.clear() , ms.insert(in[i]) , f[i][i] = inf; 23 for(int j=i+1;j<=n;j++) { 24 f[i][j] = f[i][j-1]; 25 if( ms.find(in[j]) != ms.end() ) { f[i][j] = 0; continue; } 26 multiset<int>::iterator it = ms.lower_bound(in[j]); 27 if( it != ms.end() ) f[i][j] = min( f[i][j] , *it - in[j] ); 28 if( it != ms.begin() ) f[i][j] = min( f[i][j] , in[j] - *--it ); 29 if( j - i + 1 >= k ) ans = max( ans , (lli) f[i][j] * ( j - i ) ); 30 ms.insert(in[j]); 31 } 32 } 33 printf("%lld ",ans); 34 } 35 } 36 namespace Sol { 37 int Log[maxn],mxl; 38 39 struct RMQ_Min { 40 int dat[maxn][20]; 41 int& operator [] (const int &x) { return *dat[x]; } 42 inline void rebuild() { 43 for(int j=1;j<=mxl;j++) for(int i=1;i<=n;i++) dat[i][j] = min( dat[i][j-1] , dat[i+(1<<(j-1))][j-1] ); 44 } 45 inline int query(int l,int r) { 46 int L = Log[r-l+1]; 47 return min( dat[l][L] , dat[r-(1<<L)+1][L] ); 48 } 49 }rmqmi; 50 51 struct RMQ_Max { 52 int dat[maxn][20]; 53 int& operator [] (const int &x) { return *dat[x]; } 54 inline void rebuild() { 55 for(int j=1;j<=mxl;j++) for(int i=1;i<=n;i++) dat[i][j] = max( dat[i][j-1] , dat[i+(1<<(j-1))][j-1] ); 56 } 57 inline int query(int l,int r) { 58 int L = Log[r-l+1]; 59 return max( dat[l][L] , dat[r-(1<<L)+1][L] ); 60 } 61 }rmqmx; 62 63 struct SemgnetTree_Min { 64 int l[maxn<<3],r[maxn<<3],lson[maxn<<3],rson[maxn<<3],dat[maxn<<3],cnt; 65 inline void build(int pos,int ll,int rr) { 66 l[pos] = ll , r[pos] = rr , dat[pos] = inf; 67 if( ll == rr ) return; 68 const int mid = ( ll + rr ) >> 1; 69 build(lson[pos]=++cnt,ll,mid) , build(rson[pos]=++cnt,mid+1,rr); 70 } 71 inline void update(int pos,const int &tar,const int &x) { 72 if( l[pos] == r[pos] ) return void( dat[pos] = x ); 73 const int mid = ( l[pos] + r[pos] ) >> 1; 74 tar <= mid ? update(lson[pos],tar,x) : update(rson[pos],tar,x) , dat[pos] = min( dat[lson[pos]] , dat[rson[pos]] ); 75 } 76 inline int query(int pos,const int &ll,const int &rr) { 77 if( ll <= l[pos] && r[pos] <= rr ) return dat[pos]; 78 const int mid = ( l[pos] + r[pos] ) >> 1; 79 if( rr <= mid ) return query(lson[pos],ll,rr); 80 else if( ll > mid ) return query(rson[pos],ll,rr); 81 return min( query(lson[pos],ll,rr) , query(rson[pos],ll,rr) ); 82 } 83 inline void reset() { cnt = 1; } 84 }sgtmi; 85 86 struct SemgnetTree_Max { 87 int l[maxn<<3],r[maxn<<3],lson[maxn<<3],rson[maxn<<3],dat[maxn<<3],cnt; 88 inline void build(int pos,int ll,int rr) { 89 l[pos] = ll , r[pos] = rr , dat[pos] = minf; 90 if( ll == rr ) return; 91 const int mid = ( ll + rr ) >> 1; 92 build(lson[pos]=++cnt,ll,mid) , build(rson[pos]=++cnt,mid+1,rr); 93 } 94 inline void update(int pos,const int &tar,const int &x) { 95 if( l[pos] == r[pos] ) return void( dat[pos] = x ); 96 const int mid = ( l[pos] + r[pos] ) >> 1; 97 tar <= mid ? update(lson[pos],tar,x) : update(rson[pos],tar,x) , dat[pos] = max( dat[lson[pos]] , dat[rson[pos]] ); 98 } 99 inline int query(int pos,const int &ll,const int &rr) { 100 if( ll <= l[pos] && r[pos] <= rr ) return dat[pos]; 101 const int mid = ( l[pos] + r[pos] ) >> 1; 102 if( rr <= mid ) return query(lson[pos],ll,rr); 103 else if( ll > mid ) return query(rson[pos],ll,rr); 104 return max( query(lson[pos],ll,rr) , query(rson[pos],ll,rr) ); 105 } 106 inline void reset() { cnt = 1; } 107 }sgtmx; 108 109 int liml[maxn],limr[maxn]; 110 111 inline bool judge(int l,int r) { 112 int ll = rmqmx.query(l,r) , rr = rmqmi.query(l,r); 113 return ll <= l && r <= rr; 114 } 115 inline int binrit(int curl,int l,int r) { 116 if( judge(curl,r) ) return r; 117 int mid; 118 while( r > l + 1 ) { 119 mid = ( l + r ) >> 1; 120 if( judge(curl,mid) ) l = mid; 121 else r = mid; 122 } 123 return l; 124 } 125 inline int triseg(int pos) { // if same move l . 126 int l = liml[pos] , r = pos , lmid , rmid , tpl; 127 int cl , cr , ret = -inf; 128 while( r > l + 2 ) { 129 lmid = ( l + l + r ) / 3 , rmid = ( l + r + r ) / 3; 130 131 tpl = rmqmi.query(lmid,pos); 132 if( tpl < pos ) cl = -inf; 133 else cl = binrit(lmid,pos,limr[pos]) - lmid; 134 135 tpl = rmqmi.query(rmid,pos); 136 if( tpl < pos ) cr = -inf; 137 else cr = binrit(rmid,pos,limr[pos]) - rmid; 138 139 if( cl <= cr ) l = lmid; 140 else r = rmid; 141 } 142 for(int i=l;i<=r;i++) { 143 tpl = rmqmi.query(i,pos); 144 if( tpl < pos ) continue; 145 ret = max( ret , binrit(i,pos,limr[pos]) - i ); 146 } 147 return ret; 148 } 149 inline int getmxseg(int lim) { 150 int ret = -inf; 151 sgtmi.reset() , sgtmi.build(1,1,1e5); 152 for(int i=n;i;i--) limr[i] = rmqmi[i] = min(sgtmi.query(1,in[i]-lim+1,in[i]+lim-1)-1,n) , sgtmi.update(1,in[i],i); 153 sgtmx.reset() , sgtmx.build(1,1,1e5); 154 for(int i=1;i<=n;i++) liml[i] = rmqmx[i] = max(sgtmx.query(1,in[i]-lim+1,in[i]+lim-1)+1,1) , sgtmx.update(1,in[i],i); 155 rmqmi.rebuild() , rmqmx.rebuild(); 156 for(int i=1;i<=n;i++) { 157 ret = max( ret , triseg(i) ); 158 } 159 return ret >= k ? ret : -inf; 160 } 161 inline lli tri1() { // WAWAWA 162 int l = 1 , r = lim , lmid , rmid; 163 lli cl , cr , ret = -lli_inf; 164 while( r > l + 2 ) { 165 lmid = ( l + l + r ) / 3 , rmid = ( l + r + r ) / 3; 166 cl = (lli) lmid * getmxseg(lmid) , cr = (lli) rmid * getmxseg(rmid); 167 if( cl <= cr ) l = lmid; 168 else r = rmid; 169 } 170 for(int i=l;i<=r;i++) ret = max( ret , (lli) i * getmxseg(i) ); 171 return ret; 172 } 173 inline lli tri2() { // WAWAWA 174 int l = 1 , r = lim , lmid , rmid; 175 lli cl , cr , ret = -lli_inf; 176 while( r > l + 2 ) { 177 lmid = ( l + l + r ) / 3 , rmid = ( l + r + r ) / 3; 178 cl = (lli) lmid * getmxseg(lmid) , cr = (lli) rmid * getmxseg(rmid); 179 if( cl < cr ) l = lmid; 180 else r = rmid; 181 } 182 for(int i=l;i<=r;i++) ret = max( ret , (lli) i * getmxseg(i) ); 183 return ret; 184 } 185 186 inline void getlog() { 187 for(int i=2;i<=n;i++) Log[i] = Log[i>>1] + 1; 188 mxl = Log[n]; 189 } 190 191 inline void work() { 192 --k , getlog() , printf("%lld ",max(tri1(),tri2())); 193 } 194 } 195 196 int main() { 197 static int T; 198 scanf("%d",&T); 199 while(T--) { 200 scanf("%d%d",&n,&k); 201 for(int i=1;i<=n;i++) scanf("%d",in+i); 202 if( n <= 3e3 ) Force::work(); 203 else Sol::work(); 204 } 205 return 0; 206 }
正解代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cstdlib> 6 #define debug cout 7 typedef long long int lli; 8 using namespace std; 9 const int maxn=1e5+1e2,lim=1e5,blk=1e3; 10 const int inf=0x3f3f3f3f , minf = -inf; 11 const lli lli_inf = 0x3f3f3f3f3f3f3f3fll; 12 13 int in[maxn],n,k; 14 15 namespace Force { 16 int s[maxn]; 17 inline void work() { 18 lli ans = -lli_inf; 19 memset(s,0x3f,sizeof(s)); 20 for(int i=n;i;i--) { 21 for(int j=i+1;j<=n/*&&j<=i+blk*/;j++) { 22 s[j] = min( s[j] , abs(in[i]-in[j]) ) , s[j] = min( s[j] , s[j-1] ); 23 if( j - i >= k )ans = max( ans , (lli) s[j] * ( j - i ) ); 24 if( (lli) s[j] * ( n - i ) <= ans ) break; 25 } 26 } 27 printf("%lld ",ans); 28 } 29 } 30 31 int main() { 32 static int T; 33 scanf("%d",&T); 34 while(T--) { 35 scanf("%d%d",&n,&k) , --k; 36 for(int i=1;i<=n;i++) scanf("%d",in+i); 37 Force::work(); 38 } 39 }
这种题都做不出来,果然还是我太菜啦!
对了我决定把电脑里的Win10删掉以彻底杜绝自己想要推gal的思想
冷(つめ)たかった 寂(さみ)しかった
好冷啊,好寂寞
凍(い)てつく街(まち)に息衝(いきづ)く
生活在这冰封的城镇里
優(やさ)しい愛(あい)の唄(うた)が
温柔地爱的歌谣
胸(むね)の奥(おく)積(つ)もって
在心中回响
変わる景色 幼い私 隔てた 境界線(きょうかいせん
将变化的景色和幼小的自己分隔的境界线
見(み)えなくなるくらい 染(そ)めていたの
变得不再那样清晰