2018.10.20 XMYZ Day1总结
上周的忘写了……题目没有作者……
T1.backpack
期望得分100,实际得分100.
感觉我自己真是不如以前了……以前做这种题都是秒掉的,现在怎么想了10分钟啊……
因为物品的体积和价值都非常小,我们有一句套话,“远距离贪心,近距离暴力”,所以虽然背包的体积特别大,我们可以把他压缩成1000000左右,剩下的直接暴力取性价比最高的即可。
看一下代码。
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cmath> #include<set> #include<queue> #define rep(i,a,n) for(int i = a;i <= n;i++) #define per(i,n,a) for(int i = n;i >= a;i--) #define enter putchar('\n') using namespace std; typedef long long ll; const int M = 10000005; const int INF = 1000000009; const ll mod = 1e9+7; ll read() { ll ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { ans *= 10; ans += ch - '0'; ch = getchar(); } return ans * op; } ll dp[M],m,n,a[M],b[M],v[105],mpos,ans; double maxn; void solve1() { rep(i,1,n) rep(j,a[i],m) dp[j] = max(dp[j],dp[j-a[i]] + b[i]); printf("%lld\n",dp[m]); } int main() { freopen("backpack.in","r",stdin); freopen("backpack.out","w",stdout); n = read(),m = read(); rep(i,1,n) { a[i] = read(),b[i] = read(); v[a[i]] = max(b[i],v[a[i]]); } if(n <= 10000 && m <= 10000) solve1(); else { rep(i,1,100) { double p = (double)(i),q = (double)(v[i]); if(q / p > maxn) maxn = q / p,mpos = i; } if(m > 100000) { ll k = (m - 100000) / mpos; m -= k * mpos,ans += k * v[mpos]; } rep(i,1,100) rep(j,i,m) dp[j] = max(dp[j],dp[j-i] + v[i]); ans += dp[m]; printf("%lld\n",ans); } return 0; }
T2.sort
期望得分20,实际得分0.
这道题考试的时候没怎么想,主要刚T3了,而且我也不会求方案数。写了个爆搜,然后GG了。
后来想到这个最大值和最小值很好维护,最大值取后一半减去前一半即可,而最小值的话只要奇偶分别维护取差值即可。这个可以使用线段树分别维护奇偶,稍微有点麻烦,下放的时候有很多特判。
之后至于方案数,mrclr大佬说,你可以把它看成一个括号序列匹配,就是一个卡特兰数。求一下阶乘和阶乘的逆元即可。
看一下代码。
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cmath> #include<set> #include<queue> #define rep(i,a,n) for(int i = a;i <= n;i++) #define per(i,n,a) for(int i = n;i >= a;i--) #define enter putchar('\n') using namespace std; typedef long long ll; const int M = 500005; const int INF = 1000000009; const ll mod = 1e9+7; ll read() { ll ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { ans *= 10; ans += ch - '0'; ch = getchar(); } return ans * op; } struct seg { ll v,ov,ev,lazy; }t[M<<3]; ll n,m,c[M<<1],l,r,op,val,sum[M<<1],inv[M<<1]; ll qpow(ll a,ll b) { ll p = 1; while(b) { if(b&1LL) p *= a,p %= mod; a *= a,a %= mod; b >>= 1LL; } return p; } void init() { sum[0] = inv[0] = inv[1] = 1ll; rep(i,1,n<<1) sum[i] = sum[i-1] * i,sum[i] %= mod; inv[n<<1] = qpow(sum[n<<1],mod-2); per(i,(n<<1)-1,1) inv[i] = inv[i+1] * (i+1),inv[i] %= mod; //rep(i,1,n<<1) printf("%lld ",sum[i]);enter; } void pushup(int p) { t[p].v = t[p<<1].v + t[p<<1|1].v,t[p].v %= mod; t[p].ev = t[p<<1].ev + t[p<<1|1].ev,t[p].ev %= mod; t[p].ov = t[p<<1].ov + t[p<<1|1].ov,t[p].ov %= mod; } void pushdown(int p,int l,int r) { ll mid = (l+r) >> 1,k = mid - l + 1,q = r - mid; t[p<<1].v += t[p].lazy * k,t[p<<1].v %= mod; t[p<<1|1].v += t[p].lazy * q,t[p<<1|1].v %= mod; t[p<<1].lazy += t[p].lazy,t[p<<1|1].lazy += t[p].lazy; t[p<<1].lazy %= mod,t[p<<1|1].lazy %= mod; if(k & 1) { if(l&1) t[p<<1].ov += t[p].lazy * (k + 1 >> 1),t[p<<1].ev += t[p].lazy * (k>>1); else t[p<<1].ov += t[p].lazy * (k >> 1),t[p<<1].ev += t[p].lazy * (k + 1 >> 1); } else t[p<<1].ov += t[p].lazy * (k >> 1),t[p<<1].ev += t[p].lazy * (k >> 1); t[p<<1].ov %= mod,t[p<<1].ev %= mod; if(q & 1) { if((mid + 1) & 1) t[p<<1|1].ov += t[p].lazy * (q + 1 >> 1),t[p<<1|1].ev += t[p].lazy * (q >> 1); else t[p<<1|1].ov += t[p].lazy * (q >> 1),t[p<<1|1].ev += t[p].lazy * (q + 1 >> 1); } else t[p<<1|1].ov += t[p].lazy * (q >> 1),t[p<<1|1].ev += t[p].lazy * (q >> 1); t[p<<1|1].ov %= mod,t[p<<1|1].ev %= mod; t[p].lazy = 0; } void build(int p,int l,int r) { if(l == r) { t[p].v = c[l]; if(l & 1) t[p].ov = c[l]; else t[p].ev = c[l]; return; } int mid = (l+r) >> 1; build(p<<1,l,mid),build(p<<1|1,mid+1,r); pushup(p); } void modify(int p,int l,int r,int kl,int kr,ll val) { if(l == kl && r == kr) { ll k = r - l + 1; t[p].v += val * k,t[p].lazy += val; t[p].v %= mod,t[p].lazy %= mod; if(k & 1) { if(l & 1) t[p].ov += val * (k + 1 >> 1),t[p].ev += val * (k >> 1); else t[p].ov += val * (k >> 1),t[p].ev += val * (k + 1 >> 1); } else t[p].ov += val * (k >> 1),t[p].ev += val * (k >> 1); t[p].ov %= mod,t[p].ev %= mod; return; } if(t[p].lazy) pushdown(p,l,r); int mid = (l+r) >> 1; if(kr <= mid) modify(p<<1,l,mid,kl,kr,val); else if(kl > mid) modify(p<<1|1,mid+1,r,kl,kr,val); else modify(p<<1,l,mid,kl,mid,val),modify(p<<1|1,mid+1,r,mid+1,kr,val); pushup(p); } ll query(int p,int l,int r,int kl,int kr,int f) { if(l == kl && r == kr) { if(f == 1) return t[p].v; else if(f == 2) return t[p].ov; else if(f == 3) return t[p].ev; } ll mid = (l+r) >> 1; if(t[p].lazy) pushdown(p,l,r); if(kr <= mid) return query(p<<1,l,mid,kl,kr,f); else if(kl > mid) return query(p<<1|1,mid+1,r,kl,kr,f); else return query(p<<1,l,mid,kl,mid,f) + query(p<<1|1,mid+1,r,mid+1,kr,f) % mod; } int main() { freopen("sort.in","r",stdin); freopen("sort.out","w",stdout); n = read(),m = read(); init(); rep(i,1,n<<1) c[i] = read(); build(1,1,n<<1); rep(i,1,m) { op = read(); if(op == 0) l = read(),r = read(),val = read(),modify(1,1,n<<1,l,r,val); else { l = read(),r = read(); int g = (l + r) >> 1,h = (r - l + 1) >> 1; ll a = query(1,1,n<<1,l,g,1),b = query(1,1,n<<1,g+1,r,1),maxx = (b - a + mod << 1) % mod; ll ka = query(1,1,n<<1,l,r,2),kb = query(1,1,n<<1,l,r,3),minx = abs(kb - ka) % mod; ll cat = sum[h << 1] * inv[h] % mod * inv[h+1] % mod; printf("%lld %lld %lld\n",maxx >> 1,minx,cat); } } return 0; }
T3.digit
期望得分20,实际得分20.
考试的时候主要刚这题了……想到使用dp[i][j]表示前i位对4,5,6取模后结果为j的情况数,发现这个对于每一位都是一样的,可以使用矩乘优化计算。但是我的DP一直是错的……到死也没de出来。
后来发现我的计算是不对的,不应该对4,5,6分别计算,而应该对它们的lcm60取模,这样的话我们使用矩乘优化,之后取所有能整除4,5,6的数的结果即可。
看一下代码。
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cmath> #include<set> #include<queue> #define rep(i,a,n) for(int i = a;i <= n;i++) #define per(i,n,a) for(int i = n;i >= a;i--) #define enter putchar('\n') using namespace std; typedef long long ll; const int M = 60; const int INF = 1000000009; const ll mod = 1e9+7; ll read() { ll ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { ans *= 10; ans += ch - '0'; ch = getchar(); } return ans * op; } struct matrix { ll a[65][65]; void init(int x) { memset(a,0,sizeof(a)); rep(i,0,M-1) a[i][i] = x; } matrix operator * (const matrix &g) const { matrix p; p.init(0); rep(i,0,M-1) rep(j,0,M-1) rep(k,0,M-1) p.a[i][j] += a[i][k] * g.a[k][j],p.a[i][j] %= mod; return p; } matrix operator *= (const matrix &g) { return *this = *this * g; } matrix operator ^ (ll g) { matrix p,q = *this; p.init(1); while(g) { if(g & 1) p *= q; q *= q; g >>= 1; } return p; } }f,g; ll l,r,k,ans; int main() { l = read(),r = read(),k = read(); f.init(0); rep(i,0,M-1) { rep(j,0,M-1) f.a[j][i] = k / M % mod; rep(j,0,k%M-1) f.a[(i+j) % M][i]++,f.a[(i+j) % M][i] %= mod; } g = f ^ r; rep(i,0,M-1) if(i % 4 == 0 || i % 5 == 0 || i % 6 == 0) ans += g.a[i][0],ans %= mod; g = f ^ (l - 1); rep(i,0,M-1) if(i % 4 == 0 || i % 5 == 0 || i % 6 == 0) ans += (mod - g.a[i][0]),ans %= mod; printf("%lld\n",ans); return 0; }
当你意识到,每个上一秒都成为永恒。