第18周解题报告4篇(6月28日-7月4日)
1.Governing sand
题意:
给你n种树,每种树有p[i]个,每个去掉花费c[i],树高h[i]
让你去掉一些树,使得最高的树的个数占总数的一半以上
思路:
从高到底枚举树,对于第i高度的树,将更高的全部砍掉,再从低的中选取k个费用最小的砍掉。
花费为全部代价-当前高度所需花费-最多省下代价,求最小值
代码:
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<string.h>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<cmath>
#define int long long
typedef long long ll;
using namespace std;
typedef pair<int,int> PII;
const int N = 1e5+5;
const int M=205;
struct node {
int p;
int h;
int c;
}tree[N];
int c[M]; //花费为i的树的数量
bool cmp(node x, node y) {
return x.h < y.h;
}
//砍掉比最高的树小的棵数,可以省下的最多代价
int cal(ll k) {
int ans = 0, sc;
for(int i = 200; i >= 1; i--) {
sc = min(k, c[i]);
ans += sc * i;
k -= sc;//剩余还无需砍掉的数目
if(k == 0) {
return ans;
}
}
return ans;
}
signed main() {
int n;
while(cin >> n) {
for(int i = 0; i < n; i++) {
cin >> tree[i].h >> tree[i].c >> tree[i].p;
}
sort(tree, tree+n, cmp);//对树进行高度排序
memset(c, 0, sizeof(c));
int s = 0;//砍掉全部树木的花费
for(int i=0; i<n; i++){
s += tree[i].c * tree[i].p;
}
int ans = s;
int i, j;
for(i = 0; i < n; i=j){
int tot = tree[i].p;//当前高度
int cur = tree[i].p * tree[i].c;
for(j = i+1; j < n && tree[i].h == tree[j].h; j++){
tot += tree[j].p;//相同高度
cur += tree[j].p * tree[j].c;//当前高度所需花费
}
ans = min(ans, s - cur - cal(tot-1));//全部代价-当前高度所需花费-最多省下代价
for(int z = i; z < j; z++){
c[tree[z].c] += tree[z].p;
}
}
cout << ans << endl;
}
return 0;
}
2.Plus and Multipy
题意:
有一个无限的集合:
1.1在集合中
2.如果x在集合中,那么x*a和x+b也都在集合中
给定三个数字n,a,b,如果n在集合中,输出Yes,否则,输出No
思路:
当a==1的时候 此时数组中是1,1+b,1+2b,1+3b… ,直接判断(n-1)%b是否为0即可
其他的情况,找出所有小于n的a的幂,如果存在x=a^k,n%b==x%b,则存在
代码:
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<string.h>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<cmath>
#define int long long
typedef long long ll;
using namespace std;
typedef pair<int,int> PII;
signed main()
{
int t;
cin >> t;
while(t--){
int n,a,b;
cin >> n >> a >> b;
if(a==1){//特判a==1的情况 此时数组中是1,1+b,1+2b,1+3b...
if((n-1)%b==0){
cout << "Yes" << endl;
}
else{
cout << "No" << endl;
}
}
else{
int flag=0;
//找出所有小于n的a的幂,如果存在x=a^k,n%b==x%b,则存在
for (int x = 1; x <= n && !flag; x *= a){
if((n - x) % b == 0)
flag = 1;
}
if(flag){
cout << "Yes" << endl;
}
else{
cout << "No" << endl;
}
}
}
return 0;
}
3.Strange Function
题意:
令f(i)表示最小正整数x,使x不是i的除数。
求f(1)一直加到f(n)的和对1e9+7取模
思路:
f(k)能被1—i-1整除,但是不能被i整除,要计算等于f(i)的个数
答案为对于i>=1,求出n/lcm(1,2…i)的和,再加上n
代码:
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<string.h>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<cmath>
#define int long long
typedef long long ll;
using namespace std;
typedef pair<int,int> PII;
const int M=1e9+7;
int lcm(int x,int y){//求最小公倍数
return x/__gcd(x,y)*y;
}
signed main()
{
int t;
cin >> t;
while(t--){
int n;
cin >> n;
int g=1;//当前的最小公倍数
int ans=0;
for(int i=1;g<=n;i++){
g=lcm(g,i);
if(g>n){
break;
}
ans=ans+n/g;//n/lcm(1,2,...i)
}
cout << (ans+n)%M << endl;//n/lcm(1,2,...i)(i>=1)总和 再加上n
}
return 0;
}
4.Find the median
题意:
将一个数组从小到大经过排序后,中间两位数的较小那个数定义为这个数组的中位数。现初始有一个空数组,进行n次操作,每次操作插入[L,R]中的所有数组,询问每次操作后的中位数
思路:
离散化+线段树。多次插入,多次查询,考虑用线段树维护,线段树维护对于区间[l,r]内出现数的个数,同时需要标记当前区间更新次数。 需要先离散化区间,再进行建树。
代码:
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<string.h>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<cmath>
#define int long long
typedef long long ll;
using namespace std;
typedef pair<int,int> PII;
#define left lll
#define right rrr
const int N=4e5+5;
int l[N],r[N];
int x[N],y[N];
int left[4*N],right[4*N];
int add[4*N];
int sum[4*N];
int n;
int a[N];
int m,len;
void init(){//初始化,按题目要求求出数组l和r
cin>>n;
int a1,b1,c1,a2,b2,c2,m1,m2;
cin>>x[1]>>x[2]>>a1>>b1>>c1>>m1;
cin>>y[1]>>y[2]>>a2>>b2>>c2>>m2;
for(int i=3;i<=n;i++){
x[i]=(a1*x[i-1]%m1+b1*x[i-2]%m1+c1)%m1;
y[i]=(a2*y[i-1]%m2+b2*y[i-2]%m2+c2)%m2;
}
for(int i=1;i<=n;i++){
l[i]=min(x[i],y[i])+1;
r[i]=max(x[i],y[i])+1;
}
}
void makeflag(int k,int x){
add[k]+=x;
sum[k]+=x*(right[k]-left[k]+1);
}
void pushdown(int k){
if(!add[k])
return;
makeflag(k*2,add[k]);
makeflag(k*2+1,add[k]);
add[k]=0;
}
void update(int k){
sum[k]=sum[k*2]+sum[k*2+1];
}
void build(int k,int l,int r){//建线段树
if(l==r){
left[k]=a[l];
right[k]=a[l+1]-1;
return;
}
int mid=(l+r)>>1;
build(k*2,l,mid);//建左子树
build(k*2+1,mid+1,r);//建右子树
left[k]=left[k*2];
right[k]=right[k*2+1];
}
void change(int k,int l,int r,int ql,int qr){
if(ql>r||qr<l||ql>qr)
return;
if(l>=ql&&qr>=r){
makeflag(k,1);
return;
}
pushdown(k);
int mid=(l+r)>>1;
change(k*2,l,mid,ql,qr);
change(k*2+1,mid+1,r,ql,qr);
update(k);
}
int query(int k,int l,int r,ll rk){
if(l==r){
if(rk%add[k]==0)
return left[k]+rk/add[k]-1;
else
return left[k]+rk/add[k];
}
pushdown(k);
int mid=(l+r)>>1;
int ans=0;
if(rk<=sum[k*2])
ans=query(k*2,l,mid,rk);
else
ans=query(k*2+1,mid+1,r,rk-sum[k*2]);
update(k);
return ans;
}
signed main()
{
init();
//离散化区间
for(int i=1;i<=n;i++){
a[++m]=l[i];
a[++m]=r[i]+1;
}
sort(a+1,a+m+1);
// for(int i=1;i<=m;i++){
// cout << a[i] << " " ;
// }
// cout << endl;
len=1;
for(int i=2;i<=m;i++){
if(a[i]!=a[i-1]){
a[++len]=a[i];
}
}
// for(int i=1;i<=m;i++){
// cout << a[i] << " " ;
// }
// cout << endl;
build(1,1,len-1);//建树
int tot=0;
for(int i=1;i<=n;i++){
int L=lower_bound(a+1,a+len+1,l[i])-a;
int R=lower_bound(a+1,a+len+1,r[i]+1)-a-1;
// cout << L << " " << R << endl;
change(1,1,len-1,L,R);
tot+=r[i]-l[i]+1;//总数
printf("%d\n",query(1,1,len-1,(tot+1)/2));
}
return 0;
}
```

浙公网安备 33010602011771号