The 2019 ICPC China Nanchang National Invitational and International Silk-Road Programming Contest B、H

比赛链接https://www.jisuanke.com/contest/3098?view=challenges

B题 拉格朗日插值

题意  T组输入。一个n次多项式 f(x) ,每项的系数不知道,只知道f(0),f(1)..f(n) 的值,m个询问,L,R。计算$\sum_{i=L}^{R}f(i)\quad mod(9999991)$

$(1\leq T\leq 5) $

$(1\leq n\leq 1000) $

$(1\leq m\leq 2000) $

$(1\leq L\leq R \leq 9999990)$

解析 遇到这题我是崩溃的,听大家说是拉格朗日插值,找到了一个快速拉格朗日的板子,贴上去就过了。。。

#include<bits/stdc++.h>
using namespace std;
#define maxn 1010
typedef long long LL;
const LL mod = 9999991;

LL powmod(LL aa, LL x) {
    LL res = 1;
    for(; x > 0; x >>= 1) {
        if(x & 1)res = (res * aa) % mod;
        aa = (aa * aa) % mod;
    }
    return res;
}

struct lagrange {
#define ll long long
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define D 2010 //D比MAXN大100就行
    ll a[D], f[D], g[D], p[D], p1[D], p2[D], b[D], h[D][2], C[D];
    void init(int M) {//初始化:参数填MAXN + 20
        f[0] = f[1] = g[0] = g[1] = 1;
        rep(i, 2, M + 5) f[i] = f[i - 1] * i % mod;
        g[M + 4] = powmod(f[M + 4], mod - 2);
        per(i, 1, M + 4) g[i] = g[i + 1] * (i + 1) % mod;
    }
    /*给定一组样本数据a[],规模为0-d,计算出第n项*/
    ll calcn(int d, ll *a, ll n) {
        if (n <= d) return a[n];
        p1[0] = p2[0] = 1;
        rep(i, 0, d + 1) {
            ll t = (n - i + mod) % mod;
            p1[i + 1] = p1[i] * t % mod;
        }
        rep(i, 0, d + 1) {
            ll t = (n - d + i + mod) % mod;
            p2[i + 1] = p2[i] * t % mod;
        }
        ll ans = 0;
        rep(i, 0, d + 1) {
            ll t = g[i] * g[d - i] % mod * p1[i] % mod * p2[d - i] % mod * a[i] % mod;
            if ((d - i) & 1) ans = (ans - t + mod) % mod;
            else ans = (ans + t) % mod;
        }
        return ans;
    }
    /*
    给定一组观测点(0, a[0]), (1, a[1]), ...,(m, a[m]),、
    样本点的个数为a(x)的最高次+1。
    求在该函数模型下,a[0]+a[1]+...+a[n]的和。
    */
    ll ta[D];
    ll polysum(ll m, ll *a, ll n) { // 给定a[0].. a[m],求\sum_{i=0}^{n}a[i]
        memcpy(ta, a, sizeof(a[0]) * (m + 1));
        ta[m + 1] = calcn(m, ta, m + 1);
        rep(i, 1, m + 2)ta[i] = (ta[i - 1] + ta[i]) % mod;
        return calcn(m + 1, ta, n);
    }
};
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        ll a[maxn],n,m;
        scanf("%lld%lld",&n,&m);
        for(int i=0;i<=n;i++){
            scanf("%lld",&a[i]);
        }
        lagrange ri;
        ri.init(maxn+20);
        while(m--){
            ll l,r;
            scanf("%lld%lld",&l,&r);
            printf("%lld\n",(ri.polysum(n,a,r)-ri.polysum(n,a,l-1)+mod)%mod);
        }
    }
}

 

H题  FWT+线段树

题意   一个n代表A,B数组的长度,A,B两个数组中的数两两或(二进制运算)一下 ,得到一个不去重C数组(显然C的长度为n*n)。接下来一个m代表操作次数,每次输入两个数L,R

如果L等于0,表示询问C数组中第R个数,否则表示C数组中第L个数到第R个数 开根号。

解析 用FWT求出来 or 之后 每个数的个数,然后建立权值线段树,或者前缀和+二分,都可以log时间复杂度求出第k个数是几。只需要知道这个数开了几次根号,L,R会很大,

但是数量只有那么多,离散化一下就可以解决了,1e5开根号大于5次就是1了,小于5次暴力开就好了。

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
typedef long long ll;
typedef pair<int,int> Pii;
const int maxn = 3e5+10;

ll a[maxn],b[maxn],c[maxn];
void FWT_or(ll *a,int N,int opt)
{
    for(int i=1;i<=N;i<<=1)
        for(int p=i<<1,j=0;j<=N;j+=p)
            for(int k=0;k<i;++k)
                if(opt==1)a[i+j+k]=a[j+k]+a[i+j+k];
                else a[i+j+k]=a[i+j+k]-a[j+k];
}
ll C[maxn];
int lowbit(int x)
{
    return x&(-x);
}
ll bitgetsum(int x)
{
    ll ans=0;
    for(int i=x;i>0;i-=lowbit(i))
        ans+=C[i];
    return ans;
}
void bitupdate(int x,int z)
{
    for(int i=x;i<=3e5;i+=lowbit(i))
        C[i]+=z;
}
struct ndoe
{
    ll l,r;
}q[maxn];
vector<ll> v;
int getid(ll x){
    return lower_bound(all(v),x)-v.begin()+1;
}
ll sum[maxn*4];
void pushUp(int rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void build(int l,int r,int rt)
{
    if(l==r){
        sum[rt]=c[l];
        return;
    }
    int m=(l+r)>>1;
    build(l,m,rt<<1);
    build(m+1,r,rt<<1|1);
    pushUp(rt);
}
int query(ll val,int l,int r,int rt)
{
    if(l==r){
        return l;
    }
    int mid=(l+r)>>1;
    if(sum[rt<<1]>=val)
        return query(val,l,mid,rt<<1);
    else
        return query(val-sum[rt<<1],mid+1,r,rt<<1|1);
}
int main()
{
    int n,x,m;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",&x);a[x]++;
    }
    for(int i=0;i<n;i++){
        scanf("%d",&x);b[x]++;
    }
    n=2e5;
    FWT_or(a,n,1);FWT_or(b,n,1);
    for(int i=0;i<=n;i++) c[i]=1ll*a[i]*b[i];
    FWT_or(c,n,-1);build(1,n,1);
    scanf("%d",&m);
    for(int i=0;i<m;i++){
        scanf("%lld%lld",&q[i].l,&q[i].r);
        v.pb(q[i].r);
        if(q[i].l!=0)
            v.pb(q[i].l);
    }
    sort(all(v));
    v.erase(unique(all(v)),v.end());
    for(int i=0;i<m;i++){
        if(q[i].l!=0){
            bitupdate(getid(q[i].l),1);
            bitupdate(getid(q[i].r)+1,-1);
        }
        else{
            int ans,times = bitgetsum(getid(q[i].r));
            if(times>=5){
                ans=1;
            }
            else{
                ans = query(q[i].r,1,n,1);
                while(times--){
                    ans=floor(sqrt(ans));
                }
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}

 

posted @ 2019-07-30 15:55  灬从此以后灬  阅读(323)  评论(0编辑  收藏  举报