7.9模拟赛

dp专场既视感

T1.gift

有约束的背包。

先把原序列排序,从小到大,对于其中第x个元素,我们假设它是最小的没有被选的物品,那么小于a[x]的都要被强制选择。

这就会影响统计答案的区间,变成( m-s[i-1],m-s[i] ]。

其余正常转移即可。

#include<algorithm>
#include<iostream>
#include<cstdio>

using namespace std;

const int MAXN=1005;
const int MOD=1e9+7;


int f[MAXN];
int a[MAXN],s[MAXN];

int n,m,ans;

int main(){
    cin>>n>>m;
    f[0]=1;
    for(int i=1;i<=n;i++) cin>>a[i];
    sort(a+1,a+1+n);
    for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
    for(int i=n;i>=1;i--){
        for(int j=m-s[i-1];j>=0&&j>m-s[i];j--)(ans+=f[j])%=MOD;
        for(int j=m;j>=a[i];j--)(f[j]+=f[j-a[i]])%=MOD;
    }
    if(s[n]<=m) ans++;
    cout<<ans%MOD;
    return 0;
}

 T2.fseq

求概率,想到分母肯定是C(n+m,n),可是分子呢。。

把+1看成向右走,-1看成向上走,就是在一个N*M的网格图中从原点走到(N,M)的方案数了,这是一个不降路径问题 ,答案为C(n+m,n)

可是这里说任意前缀和不能小于0,所以我们可以形象化这个约束条件,也就是不穿过对角线,神奇的卡特兰数来了。

(C(n+m,n)-C(n+m,n-1))/C(n+m,n)

化简以后就是1-m/(n+1)

代码实现,注意m>n的情况要特判。

 

#include<iostream>
#include<cstdio>

using namespace std;

int n,m,T;
int main(){
    cin>>T;
    while(T--){
        cin>>n>>m;
        if(n<m){
            puts("0.000000");
            continue;
        }
        printf("%.6lf\n",1.0-m*1.0/(n+1.0));
    }
    return 0;
}

 T3.lucky

看起来是数位DP,可以用递归的形式做。

这个问题有明显的子问题性质,对于一个长度为n的数,我们可以分开它的前n-1位和第n位进行考虑,而前n-1位就又是一个子问题了。

考虑计算一个长度为n的数的第x位,它若是等于对称的n-x+1位,那就直接返回。

从中间分开这个序列,前半部分是可以随意填写的,而后半部分就要受到约束(反之亦然成立),约束是一一对应的,所以前半部分是10为底的幂,后半部分是9为底的幂。

预处理形如999...999的数,可以在累计答案时直接加入。

GSH真是太强啦

#include<iostream>
#include<cstdio>
#define int long long
using namespace std;

const int MAXLEN=20;

int po(int x,int y){
  int ret=1;
  for(int base=x;y;y>>=1,base*=base) if(y&1) ret*=base;
  return ret;
}

int a[MAXLEN],res[MAXLEN],bp;
int len;

int calc(int x){
  int tmp=a[x],ans=0ll;
  if(x==len||(x<bp&&a[x]>a[len-x+1])) tmp--;
  ans+=tmp*po(10,max(0ll,x-bp))*po(9ll,min(x-1,bp-1));
  if(x<bp&&a[x]==a[len-x+1]) return ans;
  if(x==1) return ans+1ll;
  ans+=calc(x-1);
  return ans;
}

int solve(int x){
  len=0;
  if(x==0) return 0;
  int ans=0;
  while(x){
    a[++len]=x%10;
    x/=10;
  }
  ans+=res[len-1];
  bp=(len/2)+1;
  ans+=calc(len);
  return ans;
}

void prework(){
  for(int i=1,tmp=9;i<=18;i++,tmp=tmp*10+9) res[i]=solve(tmp);
}

signed main(){
  int na,nb;
  cin>>na>>nb;
  prework();
  cout<<solve(nb)-solve(na-1);
  return 0;
}

 

 

posted @ 2018-07-09 20:05  GhostCai  阅读(126)  评论(0编辑  收藏  举报