这题纠结了好久。
状态转移,预处理的话要1024*1024*10*10,感觉会T,然后发现 9 当成 0 就变成了 512*512*9*9,于是就这么写了。
然后 T 了好久, 然后各种改 , IO加速。能加 inline 的都加 inline 。 依然 TLE 。
后来找一下别人的代码 , 发现 查询的时候 , 我是在每个查询里面 分别再查询 左右值。别人都放一个结构体里面,这样别人的事logN,我的事logN*logN。
改了之后,WA。
想到不能区分 0 和 9 然后尝试各种区分0和9. 各种wa 。
矩阵看来还是要用1024*1024的。不能这么预处理啊。写一个记忆化的函数吧。然后这个想法又迅速被自己泯灭了。我就是不想这么写。烦死了。
后来死的次数多了,就无所谓了 , 曾经被自己否决的预处理 , 试试吧。预处理 1024*1024*10*10。 625ms。瞬间激动之情难以言表。
每一段存 4 个值。本区间的数根val[0, 9]。前缀可达状态Left[0, 1023] 。后缀可达状态Right[0, 1023]。区间可达状态sum[0, 1023]。
状态转移见代码吧。各种亦或。
const int N = 100002;
__int16 tri_one[1030][10]; //tri_one[a][b] 表示 状态a加上一个数b
__int16 tri_sum[1030][1030]; //表示 a 边和 b 左边一定连着。
__int16 val[N<<2], sum[N<<2], Left[N<<2], Right[N<<2];
__int16 bit[10];
int n;
void init()
{
for(__int16 i=0; i<=9; i++) bit[i] = 1<<i;
}
void in(__int16 &a)
{
a = 0;
char ch;
while(ch=getchar(), ch<'0'||ch>'9');
while(ch>='0'&&ch<='9') a = a*10+ch-'0', ch=getchar();
}
void inn(int &a)
{
a = 0;
char ch;
while(ch=getchar(), ch<'0'||ch>'9');
while(ch>='0'&&ch<='9') a = a*10+ch-'0', ch=getchar();
}
inline __int16 to(__int64 x)
{
if(x==0) return 0;
x %= 9;
return x==0?9:x;
}
void make_one()
{
__int16 a, b;
for(a=0; a<1024; a++)
for(b=0; b<=9; b++)
{
__int16 ans = 0;
for(__int16 i=0; i<=9; i++)
if( a & bit[i] )
{
ans |= bit[ to(i+b) ];
}
tri_one[a][b] = ans;
}
}
void make_sum()
{
__int16 a, b;
for(a=0; a<1024; a++)
for(b=0; b<1024; b++)
{
__int16 ans = a|b;
for(int i=0; i<=9; i++)
if(a&bit[i])
{
for(int j=0; j<=9; j++)
if(b&bit[j])
{
ans |= bit[ to(i+j) ];
if(ans==1023) break;
}
if(ans==1023) break;
}
tri_sum[a][b] = ans;
}
}
void build(int l, int r, int k)
{
if(l==r)
{
int x;
inn(x);
x = to(x);
val[k] = x;
x = 1<<x;
sum[k] = Left[k] = Right[k] = x;
return ;
}
int mi = (l+r)>>1;
int lk = k<<1, rk = k<<1|1;
build(l, mi, lk);
build(mi+1, r, rk);
val[k] = to(val[lk]+val[rk]);
Left[k] = Left[lk]|tri_one[Left[rk]][val[lk]];
Right[k] = Right[rk]|tri_one[Right[lk]][val[rk]];
sum[k] = sum[lk]|sum[rk];
sum[k] |= tri_sum[Right[lk]][Left[rk]];
}
struct node
{
__int16 val, sum, left, right;
};
void query(int l, int r, int ll, int rr, int k, node &p)
{
if(l==ll && r==rr)
{
p.sum = sum[k];
p.val = val[k];
p.left = Left[k];
p.right = Right[k];
return;
}
int mi = (ll+rr)>>1;
if(r<=mi) query(l, r, ll, mi, k<<1, p);
else if(l>mi) query(l, r, mi+1, rr, k<<1|1, p);
else
{
node lp, rp;
query(l, mi, ll, mi, k<<1, lp);
query(mi+1, r, mi+1, rr, k<<1|1, rp);
p.val = to(lp.val+rp.val);
p.left = lp.left|tri_one[rp.left][lp.val];
p.right = rp.right|tri_one[lp.right][rp.val];
p.sum = lp.sum|rp.sum;
p.sum |= tri_sum[lp.right][rp.left];
}
}
int main()
{
int t, tt=0, n, q, l, r, i, j;
init();
make_one();
make_sum();
inn(t);
while(t--)
{
inn(n);
build(1, n, 1);
inn(q);
printf("Case #%d:\n", ++tt);
while(q--)
{
inn(l), inn(r);
node p;
query(l, r, 1, n, 1, p);
__int16 res = p.sum;
i=9, j=1;
for(; ; i--)
if( res&bit[i] )
{
putchar(i+48);
i--;
break;
}
for(; i>=0 && j<5; i--)
if(res & bit[i])
{
j++;
putchar(' ');
putchar(i+48);
}
while(j++ < 5)
{
putchar(' ');
putchar('-');
putchar('1');
}
putchar('\n');
}
if(t) putchar('\n');
}
return 0;
}