51nod 1989 竞赛表格 【暴力搜索合法状态】

题目传送门

题目分析:

表格这么大,显然需要一些奇妙的剪枝。
小学生告诉你
a b c d e ‾ + e d c b a ‾ = 10001 ( a + e ) + 1010 ( b + d ) + 200 c \overline{abcde}+\overline{edcba}=10001(a+e)+1010(b+d)+200c abcde+edcba=10001(a+e)+1010(b+d)+200c
a + e ∈ ( 0 , 18 ] , b + d ∈ [ 0 , 18 ] , c ∈ [ 0 , 9 ] a+e\in(0,18],b+d\in[0,18],c\in[0,9] a+e(0,18],b+d[0,18],c[0,9]
可以发现,由五位数形成的形为 x + r e v ( x ) x+rev(x) x+rev(x)的数最多只有 1 9 2 ∗ 10 19^2*10 19210个数。

所以考虑暴力把所有形为 x + r e v ( x ) x+rev(x) x+rev(x)的数全部搜出来,大概是 1 9 l e n / 2 ∗ l e n 19^{len/2}*len 19len/2len的复杂度。测试一波可以发现只有约250w个数,这就很愉快了。

把这250w个数记为S集合
记每个数在表格中的出现次数(除去第一列出现)为 f [ i ] f[i] f[i],那么对于在S集合中的每一个 j + r e v ( j ) = i j+rev(j)=i j+rev(j)=i就有 f [ i ] + = f [ j ] f[i]+=f[j] f[i]+=f[j],最后 f [ i ] f[i] f[i]还要加上由第一列的 j j j推出来的数量(其实就是dfs时的方案数)

f f f做一个前缀和,询问的时候lower_bound一下,再加上区间长度(第一列的数)就是答案。

Code:

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define LL long long
#define maxn 2666666
#define x first
#define y second
using namespace std;
char cb[1<<20],*cs,*ct;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<20,stdin),cs==ct)?0:*cs++)
template<class T>inline void read(T &a){
    char c;while(!isdigit(c=getc()));
    for(a=c-'0';isdigit(c=getc());a=a*10+c-'0');
}
int Q,ans,n,m;
LL s[maxn],pw[12],t[maxn];
pair<LL,LL>a[maxn];
void dfs(int k,int len,LL x,LL w,bool fp){
    if(x>pw[10]) return;
    if(2*k+1>len) {a[++m]=make_pair(x,w);return;}
    if(k==len-k-1) for(int i=fp?1:0;i<=9;i++) dfs(k+1,len,x+2*i*pw[k],w,0);
    else{
        if(!fp) dfs(k+1,len,x,w,0);
        for(int i=1;i<=18;i++) dfs(k+1,len,x+i*(pw[k]+pw[len-k-1]),w*(i<=9?i+!fp:19-i),0);
    }
}
inline LL rev(LL x){
    LL y=0;while(x) y=y*10+x%10,x/=10;
    return y;
}
int main()
{
    freopen("1.in","r",stdin);
    pw[0]=1;for(int i=1;i<=10;i++) pw[i]=pw[i-1]*10;
    for(int len=1;len<=10;len++) dfs(0,len,0,1,1);
    sort(a+1,a+1+m);
    for(int i=2;i<=m+1;i++)
        if(a[i].x==a[i-1].x) a[i].y+=a[i-1].y;
        else t[++n]=a[i-1].x,s[n]=a[i-1].y;
    for(int i=1;i<=n;i++)
        s[lower_bound(t+1,t+n+1,t[i]+rev(t[i]))-t]+=s[i],
        s[i]+=s[i-1];
    read(Q);
    LL L,R,P;
    while(Q--){
        read(L),read(R),read(P);
        ans^=(s[upper_bound(t+1,t+n+1,R)-t-1]-s[lower_bound(t+1,t+n+1,L)-t-1]+R-L+1)%P;
    }
    printf("%d",ans);
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值