提出 #50545493


ソースコード 拡げる

#include <bits/stdc++.h>
#include <atcoder/modint>
#include <atcoder/convolution>
const int MOD=998244353;
using mint = atcoder::static_modint<MOD>;
using namespace std;
typedef long long ll;
#define rep(i,a,n) for (ll i=a;i<(ll)(n);i++)
#define per(i,a,n) for (ll i=n;i-->(ll)(a);)
ll read(){ll r;scanf("%lld",&r);return r;}
struct fra{ll a,b;}; // z的分割 a/b, a>0,b>0 1e6, 最简分数
bool operator <(const fra&x,const fra&y){return x.a*y.b<x.b*y.a;}
bool operator ==(const fra&x,const fra&y){return x.a==y.a and x.b==y.b;};
using linear=array<ll,2>; // {b,k}: bx^0+kx^1
linear operator-(const linear&x,const linear&y){return {x[0]-y[0],x[1]-y[1]};}
using poly=vector<mint>;
poly& operator+=(poly&p0,const poly&p1){ // 多项式加法
  if(p1.size() > p0.size()) p0.resize(p1.size());
  rep(i,0,size(p1)) p0[i]+=p1[i];
  return p0;
}
poly operator*(const poly&p0,const poly&p1){ return convolution(p0,p1); }

#define N 22
// mint dp[N][N*2][N];// [i][j][k] 前i个 和i同区间的有k个,它们在[vj..vj+1]这区间里 概率
poly g[N][N*2];// [i][j][k]=sum dp[i][j][forall] 前i个和i同区间的有任意个,它们在[vj..vj+1]这区间里z^k的系数
mint inv[N];
linear sr[N*2];
tuple<double,int,linear> fr[N*2]; // {新端点, idx +左 -右, xi-? z的0次1次系数}

int main() {
  int n=read();
  vector<int> x(n+1);
  rep(i,0,n+1) x[i]=read();
  rep(i,1,n+1) inv[i]=mint(i).inv();
  vector<fra> tp;
  auto addfrac=[&](int x,int y) { int g=gcd(x,y); tp.push_back({x/g,y/g}); };
  addfrac(0,1); // 0=0/1, 不用加无限点是因为 最右[maxz,\infity)的区间方案为0, 可以省略
  rep(i,0,n+1) rep(j,i+1,n+1) { // [xi-iz,x{i+1}-iz] [xj-jz,x{j+1}-jz]
    int dx=x[j]-x[i];
    int di=j-i;
    addfrac(dx,di); // 头对头,尾对尾
    if(di>1) addfrac(dx,di-1); // xi-iz, xj-(j-1)z
    addfrac(dx,di+1); // xi-{i-1}z, xj-jz
  }
  sort(begin(tp),end(tp),[&](const fra&a,const fra&b){return a < b;}); // 排序+去重
  tp.resize(unique(begin(tp),end(tp))-begin(tp));
  mint ans=0;
  vector<int>lb(n+1,0),rb(n+1,0); // lb[区间id]=左端点顺序idx,rb[区间id]=右端点顺序idx
  rep(i,1,size(tp)) { // tp[i-1]~tp[i] 之间的排序
    double sp=(1.0*tp[i-1].a/tp[i-1].b+1.0*tp[i].a/tp[i].b)/2; // 取区间中点 来完成排序, 也可以不用double通过双端点比较完成
    rep(j,1,n+1) { // 区间[x[j-1]-jz, x[j]-jz]的端点
      fr[j*2-1]={x[j-1]-j*sp, j,{x[j-1],-j}};
      fr[j*2-0]={x[j  ]-j*sp,-j,{x[j  ],-j}};
    }
    sort(fr+1,fr+n*2+1); // 排序所有端点
    rep(j,1,n*2+1) {
      int id=get<1>(fr[j]);
      if(id>0)lb[id]=j; // 左端点
      else rb[-id]=j;
    }
    rep(j,1,n*2) sr[j] = get<2>(fr[j+1])-get<2>(fr[j]); // 区间长度 = dx+di*z
    rep(j,0,n+1) rep(k,1,n*2+1) g[j][k] = {0}; // clear;
    g[0][0] = {1};
    //g[i][j]=(sum_{c=1..maxc}(a0+a1x)^c/c!) sum g[i-1][<j],maxc=i前最多连续?个坐标在tp[i-1..i]可选
    rep(j,1,n+1) {
      poly su = {0}; // sum g[i-1][<j]
      rep(k,1,n*2+1) { // 第j个放在 第k个端点区间
        su += g[j-1][k-1];
        poly tmp = su;
        auto [a0,a1] = sr[k]; // 区间长度的 0次系数 1次系数
        rep(l,j,n+1) {
          if(k<lb[l] or rb[l]<=k)break; // lb[l] <= k < rb[l]
          tmp = tmp * poly{a0*inv[l-j+1],a1*inv[l-j+1]}; // *(a0+a1x)/(l-j+1)
          g[l][k] += tmp; // g[l][k] += (a0+a1x)^c/c! (sum g[j-1][<k]), c=l-j+1
          assert((int)g[l][k].size() <= l+1);
        }
      }
    }
    poly su = vector<mint>(n+1,0); // su = sum g[n][<k]
    rep(k,1,n*2+1) su += g[n][k];

    mint li=mint(tp[i-1].a)/tp[i-1].b;
    mint ri=mint(tp[i].a)/tp[i].b;
    rep(k,0,n+1) ans += su[k]*(ri.pow(k+1)-li.pow(k+1))/(k+1); // \int \sum a_i x^i = \sum a_i/(i+1) x^{i+1}
  }
  rep(i,0,n) ans/=(x[i+1]-x[i]); // 统一处理分母
  printf("%d\n",ans.val());
  return 0;
}

提出情報

提出日時
問題 F - Social Distance
ユーザ cromarmot
言語 C++ 20 (gcc 12.2)
得点 1000
コード長 3823 Byte
結果 AC
実行時間 87 ms
メモリ 3996 KiB

コンパイルエラー

Main.cpp: In function ‘int main()’:
Main.cpp:53:31: warning: narrowing conversion of ‘j’ from ‘ll’ {aka ‘long long int’} to ‘int’ [-Wnarrowing]
   53 |       fr[j*2-1]={x[j-1]-j*sp, j,{x[j-1],-j}};
      |                               ^
Main.cpp:54:30: warning: narrowing conversion of ‘- j’ from ‘ll’ {aka ‘long long int’} to ‘int’ [-Wnarrowing]
   54 |       fr[j*2-0]={x[j  ]-j*sp,-j,{x[j  ],-j}};
      |                              ^~
Main.cpp: In function ‘ll read()’:
Main.cpp:10:21: warning: ignoring return value of ‘int scanf(const char*, ...)’ declared with attribute ‘warn_unused_result’ [-Wunused-result]
   10 | ll read(){ll r;scanf("%lld",&r);return r;}
      |                ~~~~~^~~~~~~~~~~

ジャッジ結果

セット名 Sample All
得点 / 配点 0 / 0 1000 / 1000
結果
AC × 3
AC × 42
セット名 テストケース
Sample 00-sample-001.txt, 00-sample-002.txt, 00-sample-003.txt
All 00-sample-001.txt, 00-sample-002.txt, 00-sample-003.txt, 01-001.txt, 01-002.txt, 01-003.txt, 01-004.txt, 01-005.txt, 01-006.txt, 01-007.txt, 01-008.txt, 01-009.txt, 01-010.txt, 01-011.txt, 01-012.txt, 01-013.txt, 01-014.txt, 01-015.txt, 01-016.txt, 01-017.txt, 01-018.txt, 01-019.txt, 01-020.txt, 01-021.txt, 01-022.txt, 01-023.txt, 01-024.txt, 01-025.txt, 01-026.txt, 01-027.txt, 01-028.txt, 01-029.txt, 01-030.txt, 01-031.txt, 01-032.txt, 01-033.txt, 01-034.txt, 01-035.txt, 01-036.txt, 01-037.txt, 01-038.txt, 01-039.txt
ケース名 結果 実行時間 メモリ
00-sample-001.txt AC 1 ms 3800 KiB
00-sample-002.txt AC 1 ms 3716 KiB
00-sample-003.txt AC 86 ms 3796 KiB
01-001.txt AC 1 ms 3728 KiB
01-002.txt AC 6 ms 3692 KiB
01-003.txt AC 22 ms 3728 KiB
01-004.txt AC 1 ms 3660 KiB
01-005.txt AC 17 ms 3976 KiB
01-006.txt AC 17 ms 3848 KiB
01-007.txt AC 2 ms 3744 KiB
01-008.txt AC 1 ms 3796 KiB
01-009.txt AC 1 ms 3860 KiB
01-010.txt AC 8 ms 3652 KiB
01-011.txt AC 1 ms 3788 KiB
01-012.txt AC 60 ms 3980 KiB
01-013.txt AC 50 ms 3796 KiB
01-014.txt AC 28 ms 3840 KiB
01-015.txt AC 9 ms 3752 KiB
01-016.txt AC 66 ms 3984 KiB
01-017.txt AC 8 ms 3948 KiB
01-018.txt AC 6 ms 3788 KiB
01-019.txt AC 23 ms 3780 KiB
01-020.txt AC 25 ms 3784 KiB
01-021.txt AC 25 ms 3808 KiB
01-022.txt AC 32 ms 3804 KiB
01-023.txt AC 38 ms 3984 KiB
01-024.txt AC 31 ms 3808 KiB
01-025.txt AC 61 ms 3932 KiB
01-026.txt AC 61 ms 3936 KiB
01-027.txt AC 67 ms 3700 KiB
01-028.txt AC 71 ms 3996 KiB
01-029.txt AC 83 ms 3808 KiB
01-030.txt AC 77 ms 3996 KiB
01-031.txt AC 84 ms 3800 KiB
01-032.txt AC 78 ms 3792 KiB
01-033.txt AC 84 ms 3936 KiB
01-034.txt AC 83 ms 3880 KiB
01-035.txt AC 81 ms 3812 KiB
01-036.txt AC 84 ms 3808 KiB
01-037.txt AC 87 ms 3872 KiB
01-038.txt AC 85 ms 3796 KiB
01-039.txt AC 7 ms 3792 KiB