gym102452J Junior Mathematician 2019ICPC 香港

https://codeforces.com/gym/102452/problem/J

队友一开始就给我来了个"这不是基本操作吗"f(x)=(\sum{d(x,i)} ^2 - \sum{(d(x,i))^2})/2,于是就把要维护的东西转成只与当前坐标有关了,然后由于一个总和平方和一个每个数要分开算,且后面有个/2,那么要把m=2m,然后120空间也开不下,时间也不太行,陷入漫长的自闭

然后发现只要维护前缀和和剩下的两维就好了,没有这个/2,那么60的空间就能卡下,时间也优化了4倍,,,就简单多了

dp[k][x][y]为到第k位前缀和为x的情况下,y为前i为x和f(x)的差%m

那么假设当前选择数字i,那么转移就是dp[k][x][y]->dp[i][x+i][y+x*i-i*mi[len-i]],因为新进1位f(x)就增加前缀和*i

最后到底就只能y==0时,有一个解

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
 
const int maxl=5e3+10;
const int mod=1e9+7;
 
int llen,rlen,m,len,mt;
ll ans;
int a[maxl];
ll dp[maxl][61][61][2];
int clk[maxl][61][61][2];
int mi[maxl];
char l[maxl],r[maxl];
 
inline void prework()
{
  scanf("%s",l+1);
  llen=strlen(l+1);
  scanf("%s",r+1);
  rlen=strlen(r+1);
  scanf("%d",&m);
}
 
inline void add(ll &x,ll y)
{
  x=(x+y)%mod;
}
 
inline int mo(int x)
{
  return (x%m+m)%m;
}
 
inline ll dfs(int k,int x,int y,bool f)
{
  if(k>len)
    return y==0;
  if(clk[k][x][y][f]==mt)
    return dp[k][x][y][f];
  int up=f?a[k]:9;
  dp[k][x][y][f]=0;
  for(int i=0;i<=up;i++)
    add(dp[k][x][y][f],dfs(k+1,(x+i)%m,mo(y+x*i-mi[len-k]*i),f && (i==up)));
  clk[k][x][y][f]=mt;
  return dp[k][x][y][f];
}
 
inline void mainwork()
{
  len=rlen;mi[0]=1;++mt;
  for(int i=1;i<=len;i++)
    a[i]=r[i]-'0',mi[i]=mi[i-1]*10%m;
  ll tmp1=dfs(1,0,0,1);
  
  len=llen;++mt;
  for(int i=1;i<=len;i++)
    a[i]=l[i]-'0';  
  ll tmp2=dfs(1,0,0,1);  
  
  int x=0;
  for(int i=1;i<=llen;i++)
    x=(x+mi[llen-i]*a[i])%m;
  int fx=0;
  for(int i=1;i<llen;i++)
    for(int j=i+1;j<=llen;j++)
      fx=(fx+a[i]*a[j])%m;
  if(fx==x)
    ans=((tmp1-tmp2+1)%mod+mod)%mod;
  else
    ans=((tmp1-tmp2)%mod+mod)%mod;
}
 
inline void print()
{
  printf("%lld\n",ans);
}
 
int main()
{
  int t;
  scanf("%d",&t);
  for(int i=1;i<=t;i++)
    {
      prework();
      mainwork();
      print();
    }
  return 0;
}

猜你喜欢

转载自blog.csdn.net/liufengwei1/article/details/108437142
今日推荐