181020-181021 模拟 题解
Day1
总体状态自认为不错....但是T1读错题了就很难受
以后一定要看清楚所有的细节再写题 因为不一定什么细节就能改变所有的思路
T2 Debug 70+min...其实就是细节的问题(二分边界)
所以写代码的时候一定要考虑周全
Think twice,code once.
T1 backpack 60/100
Time cost :15min
怎么可能把算法在题面里说出来啊...
天真的以为m<=1e6然后开心的O(a*m)结束..
题解里面有个结论 就是体积极大的时候可以贪心选性价比最高的到一定程度
题解用抽屉原理证了一下 这个其实考试的时候可以想成一直选到m<=1e5再做背包
Code:
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include <iostream> 5 #include<algorithm> 6 #define rep(i,a,n) for(int i = a;i <= n;++i) 7 #define per(i,n,a) for(int i = n;i >= a;--i) 8 #define inf 2147483647 9 #define ms(a,b) memset(a,b,sizeof a) 10 using namespace std; 11 typedef long long ll; 12 ll read() { 13 ll as = 0,fu = 1; 14 char c = getchar(); 15 while(c < '0' || c > '9') { 16 if(c == '-') fu = -1; 17 c = getchar(); 18 } 19 while(c >= '0' && c <= '9') { 20 as = as * 10 + c - '0'; 21 c = getchar(); 22 } 23 return as * fu; 24 } 25 //head 26 const int N = 100005; 27 ll n,m,maxid; 28 ll a[105],dp[N]; 29 30 int main() { 31 freopen("backpack.in","r",stdin); 32 freopen("backpack.out","w",stdout); 33 n = read(),m = read(); 34 rep(i,1,n) { 35 int x = read(); 36 a[x] = max(a[x],read()); 37 } 38 rep(x,1,100) { 39 if(!maxid || a[x] * maxid > a[maxid] * x) maxid = x; 40 } 41 ll cnt = (m - 1e5) / maxid; 42 ll ans = cnt * a[maxid]; 43 m -= cnt * maxid; 44 dp[0] = 0; 45 rep(i,1,100) { 46 rep(j,i,m) { 47 dp[j] = max(dp[j],dp[j-i]+a[i]); 48 } 49 } 50 printf("%lld\n",dp[m]+ans); 51 return 0; 52 }
T2 sort 100/100
Time cost : 130min
写代码不注意细节...亏大了
当时大样例要是改不过来就爆0
思路就是首先需要看出来(或者证出来)
最大值是前后一半
最小值是交叉
方案数是Catalan(因为是转化后的括号序列)
不知道为什么不少人看不出来...之前还一起研究来着
Catalan可以O(n)预处理O(1)做
关键就是交叉这个需要开两个长为n的线段树分别维护奇偶位置上的值
然后最大值就特别恶心
(最后题解开了3棵线段树...)
Code:
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #include<queue> 7 #include<vector> 8 #define ms(a,b) memset(a,b,sizeof a) 9 #define rep(i,a,n) for(int i = a;i <= n;++i) 10 #define per(i,n,a) for(int i = n;i >= a;--i) 11 #define inf 2147483647 12 using namespace std; 13 typedef long long ll; 14 ll read() { 15 ll as = 0,fu = 1; 16 char c = getchar(); 17 while(c < '0' || c > '9') { 18 if(c == '-') fu = -1; 19 c = getchar(); 20 } 21 while(c >= '0' && c <= '9') { 22 as = as * 10 + c - '0'; 23 c = getchar(); 24 } 25 return as * fu; 26 } 27 const int N = 1000005; 28 const int mod = 1e9+7; 29 //head 30 int n; 31 ll a[N]; 32 ll stp[N],stq[N]; 33 ll ksm(ll a,ll b,ll p) { 34 ll tmp = 1; 35 while(b) { 36 if(b & 1) tmp = tmp * a % p; 37 a = a * a % p; 38 b >>= 1; 39 } 40 return tmp; 41 } 42 43 ll fac[N],inv[N]; 44 void initfac() { 45 fac[0] = inv[0] = inv[1] = 1; 46 rep(i,1,n<<1) fac[i] = fac[i-1] * i % mod; 47 inv[n<<1] = ksm(fac[n<<1],mod - 2,mod); 48 per(i,(n<<1)-1,2) inv[i] = inv[i+1] * (i+1) % mod; 49 } 50 51 ll Catalan(int n) { 52 return fac[n<<1] * inv[n+1] % mod * inv[n] % mod; 53 } 54 55 ll p[N<<2],q[N<<2]; 56 ll addp[N<<2],addq[N<<2]; 57 #define ls t<<1 58 #define rs t<<1|1 59 void pup(int t) { 60 p[t] = (p[ls] + p[rs]) % mod; 61 } 62 63 void pdown(int l,int r,int t) { 64 if(!addp[t]) return; 65 int m = l+r >> 1; 66 int szl = m+1-l,szr = r-m; 67 p[ls] = (p[ls] + addp[t] * szl) % mod; 68 p[rs] = (p[rs] + addp[t] * szr) % mod; 69 addp[ls] = (addp[t] + addp[ls]) % mod; 70 addp[rs] = (addp[t] + addp[rs]) % mod; 71 addp[t] = 0; 72 } 73 74 void qup(int t) { 75 q[t] = (q[ls] + q[rs]) % mod; 76 } 77 78 void qdown(int l,int r,int t) { 79 if(!addq[t]) return; 80 int m = l+r >> 1; 81 int szl = m+1-l,szr = r-m; 82 q[ls] = (q[ls] + addq[t] * szl) % mod; 83 q[rs] = (q[rs] + addq[t] * szr) % mod; 84 addq[ls] = (addq[ls] + addq[t]); 85 addq[rs] = (addq[rs] + addq[t]); 86 addq[t] = 0; 87 } 88 89 void build(int l,int r,int t) { 90 if(l == r) { 91 p[t] = stp[l]; 92 q[t] = stq[l]; 93 return; 94 } 95 int m = l+r >> 1; 96 build(l,m,ls),build(m+1,r,rs); 97 pup(t),qup(t); 98 } 99 100 void update(int L,int R,ll c,int l,int r,int t,bool op) { 101 if(L > R) return; 102 if(L <= l && r <= R) { 103 if(op) { 104 p[t] = (p[t] + c * (r-l+1)) % mod; 105 addp[t] = (addp[t] + c) % mod; 106 } else { 107 q[t] = (q[t] + c * (r-l+1)) % mod; 108 addq[t] = (addq[t] + c) % mod; 109 } 110 return; 111 } 112 pdown(l,r,t),qdown(l,r,t); 113 int m = l+r >> 1; 114 if(L <= m) update(L,R,c,l,m,ls,op); 115 if(R > m) update(L,R,c,m+1,r,rs,op); 116 pup(t),qup(t); 117 } 118 119 ll query(int L,int R,int l,int r,int t,bool op) { 120 if(L > R) return 0; 121 if(L <= l && r <= R) return op ? p[t] : q[t]; 122 pdown(l,r,t),qdown(l,r,t); 123 int m = l+r >> 1; 124 ll ans = 0; 125 if(L <= m) ans = (ans + query(L,R,l,m,ls,op)) % mod; 126 if(R > m) ans = (ans + query(L,R,m+1,r,rs,op)) % mod; 127 return ans; 128 } 129 130 #define idx(i) (((i)+1)>>1) 131 int main() { 132 freopen("sort.in","r",stdin); 133 freopen("sort.out","w",stdout); 134 n = read(); 135 int T = read(); 136 rep(i,1,n<<1) a[i] = read(); 137 rep(i,1,n) { 138 stp[i] = a[(i<<1)-1]; 139 stq[i] = a[i<<1]; 140 } 141 initfac(),build(1,n,1); 142 while(T--) { 143 int op = read(),x = read(),y = read(); 144 if(op) { 145 ll maxx,minn,Cat; 146 int m = x+y >> 1; 147 if((x & 1) == (m & 1)) { 148 maxx = query(idx(m+1),idx(y),1,n,1,y&1) + query(idx(m+2),idx(y-1),1,n,1,x&1); 149 maxx = maxx - query(idx(x),idx(m),1,n,1,x&1) - query(idx(x+1),idx(m-1),1,n,1,y&1); 150 } else { 151 maxx = query(idx(m+2),idx(y),1,n,1,y&1) + query(idx(m+1),idx(y-1),1,n,1,x&1); 152 maxx = maxx - query(idx(x),idx(m-1),1,n,1,x&1) - query(idx(x+1),idx(m),1,n,1,y&1); 153 } 154 maxx = (maxx % mod + mod) % mod; 155 minn = query(idx(x+1),idx(y),1,n,1,(y&1)) - query(idx(x),idx(y-1),1,n,1,(x&1)); 156 minn = (minn % mod + mod) % mod; 157 Cat = Catalan(y-x+1>>1); 158 printf("%lld %lld %lld\n",maxx,minn,Cat); 159 } else { 160 ll k = read(); 161 update(idx(x),idx(y-1),k,1,n,1,(x&1)); 162 update(idx(x+1),idx(y),k,1,n,1,(y&1)); 163 } 164 } 165 return 0; 166 }
T3 digit 0/100
超级水的dp...如果心态稳一点或者代码仔细一点说不定真能AK...
50思路就是f[i][j]表示i位mod60余j有多少种情况( 60 == lcm(4,5,6) )
所以f[i][j] = ∑f[i-1][l](0<=l<k) f[0][0]=0
然后就是一个显然的矩阵乘法
发现自己会矩阵乘法 但是每次都是线性Dp不出来....
Code:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cmath> 5 #include<queue> 6 #include<vector> 7 #define C continue 8 #define B break 9 #define ms(a,b) memset(a,b,sizeof a) 10 #define rep(i,a,n) for(int i = a;i <= n;i++) 11 #define per(i,n,a) for(int i = n;i >= a;i--) 12 #define inf 3e10 13 using namespace std; 14 typedef long long ll; 15 ll read() { 16 ll as = 0,fu = 1; 17 char c = getchar(); 18 while(c < '0' || c > '9') { 19 if(c == '-') fu = -1; 20 c = getchar(); 21 } 22 while(c >= '0' && c <= '9') { 23 as = as * 10 + c - '0'; 24 c = getchar(); 25 } 26 return as * fu; 27 } 28 const int N = 60; 29 const ll mod = 1e9+7; 30 //head 31 struct Mt { 32 ll a[N][N]; 33 void init(bool op) { 34 ms(a,0); 35 rep(i,0,N-1) a[i][i] = op; 36 } 37 Mt operator * (const Mt &o) const { 38 Mt tmp;tmp.init(0); 39 rep(i,0,N-1) rep(j,0,N-1) rep(k,0,N-1) { 40 tmp.a[i][j] = (tmp.a[i][j] + (ll)a[i][k] * o.a[k][j] % mod) % mod; 41 } 42 return tmp; 43 } 44 Mt operator ^ (ll b) const { 45 Mt tmp;tmp.init(1); 46 Mt t = *this; 47 while(b) { 48 if(b & 1) tmp = tmp * t; 49 t = t * t; 50 b >>= 1; 51 } 52 return tmp; 53 } 54 }str,res; 55 bool judge(int x) { 56 if(x % 4 == 0) return 1; 57 if(x % 5 == 0) return 1; 58 if(x % 6 == 0) return 1; 59 return 0; 60 } 61 ll l,r,k,ans; 62 63 int main() { 64 freopen("digit.in","r",stdin); 65 freopen("digit.out","w",stdout); 66 l = read(),r = read(),k = read(); 67 str.init(0); 68 rep(i,0,N-1) { 69 rep(j,0,N-1) str.a[j][i] = k / N % mod; 70 rep(j,0,k % N - 1) str.a[(i + j) % N][i]++; 71 } 72 73 res = str ^ r; 74 rep(i,0,N-1) 75 if(judge(i)) ans = (ans + res.a[i][0]) % mod; 76 77 res = str ^ (l-1); 78 rep(i,0,N-1) 79 if(judge(i)) ans = (ans + mod - res.a[i][0]) % mod; 80 printf("%lld\n",ans); 81 return 0; 82 }
Day2
三道题都不会...
最后gangT1没gang过还交错了...
T1 median
其实考试的时候思路基本出来了...但是还是二分边界不熟...
做法是先假设答案在a序列里
二分a中的点(答案?) 可以得出如果这个点是答案那么应该在b中排第几
如果对的话就是答案 否则就往左右跳
Code:
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include <iostream> 5 #include<algorithm> 6 #define rep(i,a,n) for(int i = a;i <= n;++i) 7 #define per(i,n,a) for(int i = n;i >= a;--i) 8 #define inf 2147483647 9 #define ms(a,b) memset(a,b,sizeof a) 10 using namespace std; 11 typedef long long ll; 12 ll read() { 13 ll as = 0,fu = 1; 14 char c = getchar(); 15 while(c < '0' || c > '9') { 16 if(c == '-') fu = -1; 17 c = getchar(); 18 } 19 while(c >= '0' && c <= '9') { 20 as = as * 10 + c - '0'; 21 c = getchar(); 22 } 23 return as * fu; 24 } 25 //head 26 const int N = 500005; 27 int n,m,ans; 28 int a[N],b[N]; 29 30 int calc(int *a,int *b,int l1,int r1,int l2,int r2) { 31 int Rnk = r1 - l1 + 1 + r2 - l2 + 1 >> 1,l = l1,r = r1; 32 while(l <= r) { 33 int m = l+r >> 1; 34 int rnkb = Rnk - (m-l1+1) + l2; 35 if(rnkb == l2 - 1 && Rnk == m-l1 && a[m] <= b[l2]) return a[m]; 36 else if(rnkb < l2) r = m - 1; 37 else if(rnkb > r2) l = m + 1; 38 else if(a[m] >= b[rnkb] && (a[m] <= b[rnkb+1] || rnkb == r2)) return a[m]; 39 else if(a[m] >= b[rnkb]) r = m-1; 40 else l = m+1; 41 } 42 return 0; 43 } 44 45 46 int main() { 47 freopen("median.in","r",stdin); 48 freopen("median.out","w",stdout); 49 n = read(),m = read(); 50 rep(i,1,n) a[i] = read(); 51 rep(i,1,n) b[i] = read(); 52 rep(i,1,m) { 53 int op = read(); 54 if(op == 1) { 55 int x = read(),y = read(),z = read(); 56 x ? b[y] = z : a[y] = z; 57 } else { 58 int l1 = read(),r1 = read(),l2 = read(),r2 = read(); 59 if(ans = calc(a,b,l1,r1,l2,r2)) printf("%d\n",ans); 60 else printf("%d\n",calc(b,a,l2,r2,l1,r1)); 61 } 62 } 63 return 0; 64 } 65