2017 Multi-University Training Contest

2017 Multi-University Training Contest - Team 4

03  / hdu6069    数学,素数筛

题意: d(n)表示 n 的因子个数,求 d(i^k),l<=i<=r 。

tags: 算术基本定理拆开,然后素数筛过去。

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (ll i=a; i<=b; ++i)
#define per(i,b,a) for (ll i=b; i>=a; --i)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MP make_pair
#define PB push_back
#define fi  first
#define se  second
typedef long long ll;
const ll N = 1000105, mod = 998244353;

ll  l, r, k, ans[N], pri[N], num[N];
int tot;
bool  mark[N];
void getprime()
{
    for(int i=2; i<N; ++i) if(mark[i]==0) {
        pri[++tot]=i;
        for(int j=i+i; j<N; j+=i)  mark[j]=1;
    }
}
void Init()
{
    for(int i=0; i<N; ++i) ans[i]=1;
    for(ll i=l; i<=r; ++i) num[i-l] = i;
}
int main()
{
    getprime();
    int T;   scanf("%d", &T);
    while(T--)
    {
        scanf("%lld%lld%lld", &l, &r, &k);
        Init();
        for(int ca=1; ca<=tot && pri[ca]<=r; ++ca)
        {
            ll p=pri[ca], x=p;
            if(p<l)  x = (l+p-1)/p*p;
            for(ll x1=x; x1<=r; x1+=p)
            {
                ll cnt1=0;
                while(num[x1-l]%p==0) ++cnt1, num[x1-l]/=p;
                ( ans[x1-l] *= (k*cnt1+1)%mod ) %= mod ;
            }
        }
        ll  ans1=0;
        for(ll i=l; i<=r; ++i) if(num[i-l] != 1) ( ans[i-l] *= k+1 ) %= mod;
        for(ll i=l; i<=r; ++i)  ( ans1 += ans[i-l] ) %= mod;
        printf("%lld
", (ans1+mod)%mod);
    }

    return 0;
}
View Code

04 / hdu6070    最优比率,二分+线段树维护

题意:给出n个的提交的题目的标号,求任意一个区间最小的AC率。

tags: 这个 二分+线段树 很神奇,根本想不到。。

官方题解:二分答案mid,检验是否存在一个区间满足size(l,r)/(r−l+1) ≤ mid,式子变化一下就是:size(l,r) + mid​*l​​ ≤ mid*(r+1) 。从左往右枚举每个位置作为r,当r变化为r+1时,对size的影响是一段区间加1,线段树维护区间最小值即可。时间复杂度O(n*logn*logw)。

最关键的是想到这个式子变化为 size(l,r)+mid*l ,然后在线段树中维护 size(l,r)+mid*l 。 而从左往右枚举右端点 ,即利用线段树累加省去了枚举左端点的操作,和 CF 833B  有点像 。

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MP make_pair
#define PB push_back
#define fi  first
#define se  second
typedef long long ll;
const int N = 60005;
const double eps = 1e-6;

int n, pre[N], now[N], a[N];
double lazy[N<<4], tr[N<<4];
void pushup(int ro)
{
    tr[ro] = min(tr[ro<<1], tr[ro<<1|1]);
}
void build(int ro, int l, int r, double v)
{
    lazy[ro] = 0, tr[ro] = v*l;
    if(l==r) return ;
    int mid = l+r>>1;
    build(ro<<1, l, mid, v);
    build(ro<<1|1, mid+1, r, v);
    pushup(ro);
}
void tag(int ro, double v)
{
    lazy[ro] += v, tr[ro] += v;
}
void pushdown(int ro)
{
    if(lazy[ro]>eps)
    {
        tag(ro<<1, lazy[ro]);
        tag(ro<<1|1, lazy[ro]);
        lazy[ro] = 0;
    }
}
void update(int ro, int l, int r, int ql, int qr, double v)
{
    if(ql<=l && r<=qr) {
        tag(ro, v);
        return ;
    }
    pushdown(ro);
    int mid = l+r>>1;
    if(ql<=mid) update(ro<<1, l, mid, ql, qr, v);
    if(mid<qr) update(ro<<1|1, mid+1, r, ql, qr, v);
    pushup(ro);
}
double query(int ro, int l, int r, int ql, int qr)
{
    if(ql<=l && r<=qr) return tr[ro];
    pushdown(ro);
    int mid = l+r>>1;
    double mi = 1e18;
    if(ql<=mid) mi = min(mi, query(ro<<1, l, mid, ql, qr));
    if(mid<qr) mi = min(mi, query(ro<<1|1, mid+1, r, ql, qr));
    return mi;
}
bool check(double x)
{
    build(1, 1, n, x);
    rep(i,1,n)
    {
        update(1, 1, n, pre[i]+1, i, 1);
        if(query(1, 1, n, 1, i) <= x*(i+1)) return true;
    }
    return false;
}
int main()
{
    int T;  scanf("%d", &T);
    while(T--)
    {
        mes(now, 0);
        scanf("%d", &n);
        rep(i,1,n)
        {
            scanf("%d", &a[i]);
            pre[i] = now[a[i]], now[a[i]] = i;
        }
        double l=0, r=1.0, mid;
        //rep(ca,0,25)
        while(fabs(r-l)>eps)
        {
            mid = (l+r)/2;
            if(check(mid)) r=mid;
            else l=mid;
        }
        printf("%.5f
", mid);
    }

    return 0;
}
View Code

 12 / hdu6078   dp+树状数组优化

题意:定义了''wavel''序列为:a1<a2>a3<a4>a5<a6... 求f()和g()的方案数。

tags:看不懂题解怎么写的,但树状数组优化卡过去了。。

dp[i][j][1/0] 表示a[i]与b[j]相同时,a[i] 作为最后一个波谷/波峰的方案数。

转移:dp[i][j][1] = max(dp[x][y][0]) ,  (x<i, y<j, a[x]>a[i], a[x]==b[y]) ;    dp[i][j][0] = max(dp[x][y][1]) ,  (x<i, y<j, a[x]<a[i], a[x]==b[y]) 。

所以对于 dp[i][j][1],只要找比 a[i] 先出现且比它大的 a[x] 有多少个,进行递推即可。 dp[i][j][0] 同理。

//  4
#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MP make_pair
#define PB push_back
#define fi  first
#define se  second
typedef long long ll;
const int N = 2005, mod = 998244353;

int n, m, a[N], b[N], mx;
ll  dp[N][N][2], bit[N][2];
void Add(int x, ll v, int flag) {
    for(; x<=mx; x+=x&-x) ( bit[x][flag] += v ) %= mod;
}
ll  Sum(int x, int flag) {
    ll ans=0; for(; x>0; x-=x&-x) ans = (ans+bit[x][flag])%mod; return ans;
}
int main()
{
    int T;  scanf("%d", &T);
    while(T--)
    {
        scanf("%d%d", &n, &m);
        mx = 0;
        rep(i,1,n) scanf("%d", &a[i]), mx = max(mx, a[i]);
        rep(i,1,m) scanf("%d", &b[i]), mx = max(mx, b[i]);
        mes(dp, 0);
        ll  ans = 0;
        rep(i,1,n)
        {
            rep(j,1,m) {
                ( dp[i][j][0] += dp[i-1][j][0] ) %= mod;
                ( dp[i][j][1] += dp[i-1][j][1] ) %= mod;
            }
            rep(j,0,mx)
                bit[j][0] = bit[j][1] = 0;
            rep(j,1,m)
            {
                if(a[i]==b[j])
                {
                    ll  tmp1 = Sum(b[j]-1, 1), tmp2 = Sum(mx, 0)-Sum(b[j], 0);
                    ( dp[i][j][0] += tmp1 ) %= mod;
                    ( dp[i][j][1] += tmp2+1 ) %= mod;
                    ( ans += (tmp1+tmp2+1)%mod ) %= mod;
                }
                Add(b[j], dp[i-1][j][0], 0);
                Add(b[j], dp[i-1][j][1], 1);
            }
        }
        printf("%lld
", (ans+mod)%mod);
    }

    return 0;
}
View Code
原文地址:https://www.cnblogs.com/sbfhy/p/7281448.html