半集训训练 8.28 「路,还是要自己走的」
这次吧,就是最大能力了,发挥的很正常。
自己也不再那么天真了,更追求实际的东西了。
T1 chinese
一道好题,考察的是对于公式实际意义的理解和转化题目的能力。
考场上一眼看上去啥都不会,但是看了眼数据,5以内60分,嘿嘿嘿……
打着表,就跳了这道题。
下面讲正解。
我们可以知道$f_i$的定义(炼字为i个的方案数),然后考虑$f_i*i$的实际含义。
不难发现,其含义就是炼字为i个的时候总的炼字个数。
那么$\sum \limits _{i=0}^{n*m} f_i*i$就是总的炼字的个数。
很神奇对不对!当我自说自话。
那么这样转化之后,我们发现每个点的贡献互不影响。
所以我们只需要计算每个点的贡献就可以了。
而这个贡献又由什么来确定呢?
假设$(x,y)$为炼字,那么我们就要保证$(i,y)$,$(x,j)$上的点权都要小于$(x,y)$,这些点之间的方案又互不影响,所以可以得出${(k-1)}^{n-1}*{(k-1)}^{m-1}$这个式子。
我们看出其中有些问题,也就是我们的炼字的权值不一定是$k$,这就是我们需要枚举的地方,也就是${(i-1)}^{n-1}*{(i-1)}^{m-1}$。
那么其他的点呢?当我们在算其中一个点的贡献的时候,这个点的贡献仅仅是问题转化之前的计算公式的一个分支,也就是说,我们可能会算到很多重复的情况,但在这些重复的情况中,我们只计算出来每个点的1的贡献,那么就不会在最后答案中出现算重的情况。
这也解释了为什么贡献之间互不影响。
进而,我们便可以算出其他的点的总的情况数$k^{n*m-n-m-1}$,其中$n*m-n-m-1$是除去这一行这一列的所有点,然后理解起来就很容易了。
在不同的k_i的情况下,我们的所有点的贡献都是相同的,也是因为贡献互不影响。
公式便有了 $$ans=n*m*\sum\limits _{i=0}^{k} {(i-1)}^{n-1}*{(i-1)}^{m-1}*k^{n*m-n-m-1}$$
然后我们就愉快的A掉了这道题。
小弟不才。
1 #include<cstdio> 2 #define LL long long 3 #define HZOI std 4 using namespace HZOI; 5 const int mod=1e9+7; 6 LL n,m,k; 7 LL ans; 8 inline LL Pow(LL ,LL ); 9 int main() 10 { 11 scanf("%lld%lld%lld",&n,&m,&k); 12 LL qt=Pow(k,(n*m-n-m+1)%(mod-1))%mod; 13 for (int i=1; i<=k; ++i) 14 ans=(ans+Pow(i-1,n-1)%mod*Pow(i-1,m-1)%mod*qt%mod)%mod; 15 printf("%lld\n",ans*n%mod*m%mod); 16 return 0; 17 } 18 inline LL Pow(LL x,LL y) 19 { 20 LL res=1; 21 while (y) 22 { 23 if (y&1) res=res*x%mod; 24 x=x*x%mod; 25 y>>=1; 26 } 27 return res; 28 }
T2 physics
emmmmm......
二维前缀和+暴力修改+二分答案。
O(nmqlogn)。
上天的复杂度。
可是加上剪枝即可AC,原因不明。
就是判一下我搞的这个点在不再最大的正方形里……
1 #include<cstdio> 2 #define LL long long 3 #define HZOI std 4 using namespace HZOI; 5 const int N=1e3+5; 6 LL n,m,Q; 7 LL a[N][N],sm[N][N],maxx[3][3]; 8 inline LL read(); 9 inline LL min(int a,int b) {return a<b?a:b;} 10 int main() 11 { 12 // freopen("physics3.in","r",stdin); 13 // freopen("2.out","w",stdout); 14 n=read(),m=read(),Q=read(); 15 for (int i=1,t=1; i<=n; ++i,t=1) 16 { 17 a[i][t]=getchar(); 18 while ((a[i][t]^'+') && (a[i][t]^'-')) a[i][t]=getchar(); 19 while ((a[i][t]=='+') || (a[i][t]=='-')) a[i][++t]=getchar(); 20 } 21 maxx[0][0]=-1; 22 for (int q=1,x,y; q<=Q; ++q) 23 { 24 x=read(),y=read(); 25 a[x][y]='-'; 26 if (maxx[0][0]!=-1 && (maxx[1][1]>x || maxx[2][1]<x || maxx[1][2]>y || maxx[2][2]<y)) 27 {printf("%lld\n",maxx[0][0]);continue;} 28 for (int i=1; i<=n; ++i) 29 for (int j=1; j<=m; ++j) 30 { 31 sm[i][j]=0; 32 sm[i][j]=sm[i][j-1]+sm[i-1][j]-sm[i-1][j-1]; 33 if (a[i][j]=='-') ++sm[i][j]; 34 } 35 LL l=0,r=min(n,m),nw[3][3],stop=0; 36 while (l^r) 37 { 38 int mid=(l+r>>1)+1,yn=0; 39 for (int i=1; i+mid-1<=n; ++i) 40 { 41 for (int j=1; j+mid-1<=m; ++j) 42 { 43 if (a[i][j]=='-' || a[i+mid-1][j+mid-1]=='-') continue; 44 LL num=sm[i+mid-1][j+mid-1]-sm[i+mid-1][j-1]-sm[i-1][j+mid-1]+sm[i-1][j-1]; 45 if (!num) {yn=1;nw[1][1]=i,nw[1][2]=j,nw[2][1]=i+mid-1,nw[2][2]=j+mid-1;break;} 46 } 47 if (yn) break; 48 } 49 if (yn) l=mid; else r=mid-1; 50 } 51 printf("%lld\n",l); 52 maxx[0][0]=l; 53 for (int i=1; i<=2; ++i) 54 for (int j=1; j<=2; ++j) 55 maxx[i][j]=nw[i][j]; 56 } 57 return 0; 58 } 59 inline LL read() 60 { 61 LL nn=0; char cc=getchar(); 62 while (cc<'0' || cc>'9') cc=getchar(); 63 while (cc>='0' && cc<='9') nn=(nn<<3)+(nn<<1)+(cc^48),cc=getchar(); 64 return nn; 65 }
正解待更。