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



posted @ 2021-08-06 14:00  二氧化矽  阅读(42)  评论(0)    收藏  举报