见面就想暴力,然后数据量直接劝退
题解说是莫队,确实,只要可以推出由S(i,j) 可以转移到 S(i,j+1),S(i,j-1),S(i-1,j),S(i+1,j),就符合用莫队的条件了
ps:顺便存一下组合数的模板,以前本弱竟然连这个都没存
#include
using namespace std;
typedef long long ll;
const int N = 100100;
const int mod = 1000000007;
struct Node {
int l, r;
int Index;
};
int sq;
bool operator<(const Node &a, const Node &b) {
return a.r / sq == b.r / sq? a.l < b.l: a.r < b.r;
}
int T, n, m, l, r, Max;
int ans[N];
Node node[N];
int inv[N], pro[N], invpro[N];
void Init() {
inv[1] = 1;
for(int i = 2; i < N; ++i) {
inv[i] = (ll)(mod - mod / i) * inv[mod % i] % mod;
}
pro[0] = invpro[0] = 1;
for(int i = 1; i < N; ++i) {
pro[i] = (ll)pro[i - 1] * i % mod;
invpro[i] = (ll)invpro[i - 1] * inv[i] % mod;
}
}
int get_C(int n, int m) {
if(n < m) {
return 0;
}
return (ll)pro[n] * invpro[m] % mod * invpro[n - m] % mod;
}
int main() {
Max = 0;
Init();
scanf("%d", &T);
for(int i = 0; i < T; ++i) {
scanf("%d%d", &node[i].r, &node[i].l);
node[i].Index = i;
Max = max(Max, node[i].r);
}
sq = sqrt(Max);
sort(node, node + T);
l = 1;
r = 0;
ll tmp = 1;
ll ttmp;
for(int i = 0; i < T; ++i) {
while(r < node[i].r) {
ttmp = tmp + tmp;
if(ttmp >= mod) {
ttmp -= mod;
}
tmp = ttmp - get_C(r, l);
if(tmp < 0) {
tmp += mod;
}
++r;
}
while(l > node[i].l) {
tmp = tmp - get_C(r, l);
if(tmp < 0) {
tmp += mod;
}
--l;
}
while(r > node[i].r) {
ttmp = tmp + get_C(r - 1, l);
if(ttmp >= mod) {
ttmp -= mod;
}
tmp = (ttmp * inv[2]) % mod;
--r;
}
while(l < node[i].l) {
tmp = tmp + get_C(r, l + 1);
if(tmp >= mod) {
tmp -= mod;
}
++l;
}
ans[node[i].Index] = tmp;
}
for(int i = 0; i < T; ++i) {
printf("%d\n", ans[i]);
}
return 0;
}
遇事不决先打表,然后就可以发现它是以2L为循环节的,然后就是二维前缀和的一些操作
#include
using namespace std;
typedef long long ll;
const int N = 100 + 100;
int T, n, q;
int a[N];
ll num[N][N];
ll Sum(int x, int y) {
if(x < 0 || y < 0) {
return 0;
}
int nn = n << 1;
ll ret = num[nn - 1][nn - 1] * ((x + 1) / nn) * ((y + 1) / nn);
int xx = x % nn;
int yy = y % nn;
if(xx != nn - 1) {
ret += num[xx][nn - 1] * ((y + 1) / nn);
}
if(yy != nn - 1) {
ret += num[nn - 1][yy] * ((x + 1) / nn);
}
if(xx != nn - 1 && yy != nn - 1) {
ret += num[xx][yy];
}
return ret;
}
int main() {
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
for(int i = 0; i < n; ++i) {
scanf("%d", &a[i]);
}
int Index = 0;
for(int i = 0; i < N; ++i) {
for(int j = 0; j <= i; ++j) {
num[j][i - j] = a[Index];
Index = (Index + 1) % n;
}
}
for(int i = 0; i < N; ++i) {
for(int j = 0; j < N; ++j) {
if(i != 0) {
num[i][j] += num[i - 1][j];
}
if(j != 0) {
num[i][j] += num[i][j - 1];
}
if(i != 0 && j != 0) {
num[i][j] -= num[i - 1][j - 1];
}
}
}
scanf("%d", &q);
int x1, x2, y1, y2;
while(q--) {
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
ll ans = Sum(x2, y2) + Sum(x1 - 1, y1 - 1);
ans -= Sum(x2, y1 - 1) + Sum(x1 - 1, y2);
printf("%I64d\n", ans);
}
}
return 0;
}
耿直的搜索,先增加列标,列标到最值后增大行标列标归零
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
这一场真是考验代码能力的一场,咕咕咕
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include