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; }
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; }
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; }