2021.11.16 测试
T1:寻找宝藏
对于原矩阵维护一个二维前缀和和后缀和,这样宝藏的数目就可以在两个点对上统计贡献,枚举其中一个点对,用 3*k个树状数组 寻找另一个点即可(本题的精髓,详见代码中//★★★ //*1)
*0:题意
绿色部分算作两次!
*1:(如上图)
//f[]:矩阵前缀和
//g[]:矩阵后缀和
S阴影 (即k)=(f[x1][y1]+g[x2][y2])-(g[x1+1][y1+1]+f[x2-1][y2-1])
=(f[x1][y1]-g[x1+1][y1+1])-(f[x2-1][y2-1]-g[x2][y2])
=f ' [x1][y1]-f ' [x2-1][y2-1]
=k
=>f ' [x2-1][y2-1]=f ' [x1][y1]-k
=>f ' (x2-1,y2-1)的对应值为f ' (x1,y1)-k
*2:
x1(i'),x2(i)∈[1,n]
y1(j'),y2(j)∈[1,m]
#include<bits/stdc++.h> using namespace std; char ch; int res; const int N=100003,M=103,K=100003; inline int rd() { while((ch=getchar())<'0'||'9'<ch); res=ch-'0'; while((ch=getchar())>='0'&&ch<='9')res=(res<<1)+(res<<3)+ch-'0'; return res; } int n,m,k,cnt,f[N][M],g[N][M]; long long ans; struct BIT { int t[M];//树状数组 //★★★ void update(int x) { for(;x<M;x+=(x&-x))t[x]++; } int query(int x)//★★★ { int numm=0; for (;x;x-=(x&-x))numm+=t[x]; return numm; } }s[K*3]; int main() { n=rd(),m=rd(),k=rd(); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { while((ch=getchar())^'.'&&ch^'$'); f[i][j]=f[i-1][j]+f[i][j-1]-f[i-1][j-1]; if(ch^'.')f[i][j]++,g[i][j]++,cnt++; } } for(int i=n;i>=1;i--) for(int j=m;j>=1;j--) g[i][j]+=g[i+1][j]+g[i][j+1]-g[i+1][j+1]; for(int i=0;i<=n;i++) for(int j=0;j<=m;j++) f[i][j]-=g[i+1][j+1];//*1 for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) s[f[i-1][j-1]+2*cnt].update(j);//*1&*2 for(int j=1;j<=m;j++) ans+=s[f[i][j]-k+2*cnt].query(j);//*1&*2 //+2*cnt:防止下标为负报错 (cnt-f[i][j]) 与 (cnt-k) } cout<<ans; }
T2:分身
f : 贡献的前缀和
fi=[fi-1+(ai+fi-1)/(n-1)]%mod
=[fi-1+(ai+fi-1)]*逆元(n-1)%mod
a[i]的值即为其后的值做出的总贡献,即(fn-fi)
#include<bits/stdc++.h> #define int unsigned long long using namespace std; char ch; int res; inline int rd() { while((ch=getchar())<'0'||'9'<ch); res=ch-'0'; while((ch=getchar())>='0'&&ch<='9')res=(res<<1)+(res<<3)+ch-'0'; return res; } const int mod=998244353; int a[1000002]; int f[1000002]; int n,ans; int quick_pow(int x,int y) { ans=1; while(y) { if(y&1)ans=(ans*x)%mod; y>>=1; x=x*x%mod; } return ans; } int ny(int x){return quick_pow(x,mod-2);} signed main() { n=rd(); int k=ny(n-1); for(int i=1;i<=n;i++)a[i]=rd(); for(int i=1;i<=n;i++) { a[i]+=f[i-1]; f[i]=k*(f[i-1]*(n-1)%mod+a[i])%mod; } for(int i=1;i<=n;i++)cout<<(f[n]+mod-f[i])%mod<<' '; }