678C Joty and Chocolate
传送门
镜像
1600 数论
题意:n块瓷砖从1n编号,Joty可以将其中编号为a的倍数的瓷砖涂成红色,编号为b的倍数的瓷砖涂成蓝色,每涂一块红色的瓷砖可以得到p块巧克力,而蓝色的瓷砖则提供q块巧克力,最大化Joty能够得到的巧克力数。
水题,假设x块编号是a的倍数,y块编号是b的倍数,z块编号是a和b最小公倍数的倍数,当p>q的情况下,则x+z块涂成红色,y-z块涂成蓝色,其他情况同理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| #include<bits/stdc++.h> using namespace std; #define ll long long #define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0); ll n,a,b,p,q; ll gcd(ll x,ll y){if(y==0)return x;return gcd(y,x%y);} int main() { IOS cin>>n>>a>>b>>p>>q; ll m=a*b/gcd(a,b); m=n/m; a=n/a-m; b=n/b-m; ll ans; if(p>=q)ans=(a+m)*p+b*q; else ans=(b+m)*q+a*p; cout<<ans; return 0; }
|
527C Glass Carving
传送门
镜像
1800 数据结构
题意:一个长h宽w的玻璃砖,每次垂直一条边切割,问每次切割后的最大面积
开两个set和两个multiset就可以解出来了,两个set分别记录x轴和y轴上面的切割点(初始就分别扔进去0,w和0,h),multiset则记录x轴或y轴上切割产生的线段,对于每次切割后,找出当前切割点两端最近的点,然后在multiset里把这段的长度erase掉,把新生成的两段插进去,最后输出两个multiset里最大值的乘积即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| #include<bits/stdc++.h> using namespace std; #define ll long long #define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0); ll n,w,h; set<ll> x,y; multiset<ll> a,b; int main() { IOS cin>>w>>h>>n; y.insert(h);y.insert(0); x.insert(w);x.insert(0); a.insert(h); b.insert(w); while(n--){ char s; ll l; cin>>s>>l; if(s=='H'){ auto i=y.lower_bound(l); if(*i>l)i--; auto j=y.upper_bound(l); ll tmp=*i-*j; auto m=a.lower_bound(*j-*i); a.erase(m); a.insert(l-*i); a.insert(*j-l); y.insert(l); }else{ auto i=x.lower_bound(l); if(*i>l)i--; auto j=x.upper_bound(l); ll tmp=*i-*j; auto m=b.lower_bound(*j-*i); b.erase(m); b.insert(l-*i); b.insert(*j-l); x.insert(l); } auto p=a.end(),q=b.end(); q--; p--; cout<<(*p)*(*q)<<endl; } return 0; }
|
小姐姐的平衡树做法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| #include<iostream> #include<ext/pb_ds/assoc_container.hpp> #include<ext/pb_ds/tree_policy.hpp> #include<ext/pb_ds/hash_policy.hpp> using namespace std; using namespace __gnu_pbds; typedef long long ll; tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> x,y; tree<pair<int,int>,null_type,greater<pair<int,int>>,rb_tree_tag,tree_order_statistics_node_update> xx,yy; cc_hash_table<int,int> hx,hy; int w,h,n; int main() { ios::sync_with_stdio(false); cin>>w>>h>>n; x.insert(0); x.insert(w); y.insert(0); y.insert(h); xx.insert(make_pair(w,++hx[w])); yy.insert(make_pair(h,++hy[h])); for(int i=0;i<n;i++) { char c; int num; cin>>c>>num; if(c=='V') { int rank=x.order_of_key(num); int pre=*x.find_by_order(rank-1); int nxt=*x.find_by_order(rank); xx.erase(make_pair(nxt-pre,hx[nxt-pre]--)); xx.insert(make_pair(num-pre,++hx[num-pre])); xx.insert(make_pair(nxt-num,++hx[nxt-num])); x.insert(num); } else if(c=='H') { int rank=y.order_of_key(num); int pre=*y.find_by_order(rank-1); int nxt=*y.find_by_order(rank); yy.erase(make_pair(nxt-pre,hy[nxt-pre]--)); yy.insert(make_pair(num-pre,++hy[num-pre])); yy.insert(make_pair(nxt-num,++hy[nxt-num])); y.insert(num); } cout<<(ll)xx.find_by_order(0)->first*(ll)yy.find_by_order(0)->first<<endl; } return 0; }
|
1012C Hills
传送门
镜像
2000 dp
题意:一共n座山,每花费1h可以使一座山降低1的高度,最少花费多少时间可以使存在k座山的高度严格大于两侧的山的高度。输出k从1~$\lceil \frac{n}{2} \rceil$的结果。
一开始想的做法是dp[i][j][0]代表前i个有j个满足,并且最后一个不取,dp[i][j][1]代表前i个有j个满足,并且最后一个取,但是状态转移尬住了,因为还要考虑倒数第二个的状态,那开三维就好了,dp[i][j][0]代表前i个有j个满足,并且最后两个都不取,dp[i][j][2]代表前i个有j个满足,并且取最后一个,dp[i][j][1]代表前i个有j个满足,并且取倒数第二个。
那么状态转移方程就很好推了:
1 2 3
| dp[i][j][1]=dp[i-1][j][2]+max(0,a[i]-a[i-1]+1) dp[i][j][0]=min(dp[i-1][j][0],dp[i-1][j][1]) dp[i][j][2]=min(dp[i-1][j-1][0]+max(0,a[i-1]-a[i]+1),dp[i-1][j-1][1]+max(0,min(a[i-1],a[i-2]-1)-a[i]+1))
|
然后就是初始化,不确定的和非法状态存为极大值,显然dp[1][1][2]=0,并且dp[i][0][0]=0(1<=i<=n)从2开始转移就可以A了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| #include<bits/stdc++.h> using namespace std; #define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0); #define maxn 5005 int n,a[maxn],dp[maxn][maxn][3]; int main() { IOS cin>>n; for (int i = 1; i <=n ; ++i) { cin>>a[i]; for (int j = 0; j <=n ; ++j) { for (int k = 0; k <=2 ; ++k) { dp[i][j][k]=2146870000; } } dp[i][0][0]=0; } dp[1][1][2]=0; for (int i = 2; i <=n ; ++i) { for (int j = 1; j <=(i+1)/2 ; ++j) { dp[i][j][2]=min(dp[i-1][j-1][0]+max(0,a[i-1]-a[i]+1),dp[i-1][j-1][1]+max(0,min(a[i-1],a[i-2]-1)-a[i]+1)); dp[i][j][0]=min(dp[i-1][j][0],dp[i-1][j][1]); dp[i][j][1]=dp[i-1][j][2]+max(0,a[i]-a[i-1]+1); } } for (int k = 1; k <=(n+1)/2 ; ++k) { cout<<min(dp[n][k][2],min(dp[n][k][0],dp[n][k][1]))<<" "; } return 0; }
|