七月第二周周报

7.8

C题--Sequence Decomposing

求有多少个上升子序列,如果纯暴力将会超时,所以使用二分去搜。

#include<bits/stdc++.h>
using namespace std;
//#define int long long
int a[100005],b[100005],t=1;
signed main(){
    int n,a[100005];
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    for(int i=1;i<=n;i++){
        int temp=upper_bound(b+1,b+t,a[i],greater<int>())-b;
        if(temp==t){
            b[t++]=a[i];
        }
        else{
            b[temp]=a[i];
        }
    }
    cout<<t-1<<endl;
}

B题--equeue

对于一个序列有四种处理方式,分别为从左边取,从右边取,放回右边,放回左边。给定你操作次数之后,分别选择上述方式,最终使自己手里剩余最多。

贪心解决,先去决定分别从左右拿的次数,然后用剩余次数去确定从左右两侧放回的次数,最后比较每次手中剩余的数大小,选出最大的那个数。

#include<bits/stdc++.h>
using namespace std;
int n,k,v[55];
int s[105];
int i,j,sum,ia,ib,maxx;
int main(){
    std::ios::sync_with_stdio(0);
    std::cin.tie(0);
    cin>>n>>k;
    for(i=1;i<=n;i++){
        cin>>v[i];
    }
    
    for(ia=0;ia<=min(n,k);ia++){
        for(ib=0;ib<=min(n,k)-ia;ib++){
            j=0;
            sum=0;
            for(i=1;i<=ia;i++){
                s[++j]=v[i];
                sum+=v[i];
            }
            for(i=1;i<=ib;i++){
                s[++j]=v[n-i+1];
                sum+=v[n-i+1];
            }
            sort(s+1,s+1+j);
            for(int i=1;i<=min(j,k-ia-ib);i++){
                if(s[i]>0) break;
                sum-=s[i];
            }
            maxx=max(maxx,sum);
            
        }
        /*for(i=1;i<=min(j,k-ia-ib);i++){
            if(s[i]>0) break;
            sum-=s[i];
        }
        maxx=max(maxx,sum);*/
    }
    cout<<maxx<<endl;
    return 0;
}

F题--Integer Cards

为保证结果最大,则可以将原数组进行排序,也将要替换的数组进行排序,将原数组中最小的数用替换数组中最大的数进行替换,知道所替换的数组小于原数组时停止替换(确保差值最大),然后进行加和运算。

#include<bits/stdc++.h>
using namespace std;
#define int long long
priority_queue<int,vector<int>,greater<int> > q;
int n,m;
struct node{
    int bb,cc;
}e[100005];
bool cmp(node x,node y){
    return x.cc>y.cc;
}
signed main(){
    std::ios::sync_with_stdio(0);
    std::cin.tie(0);
   cin>>n>>m;
   for(int i=0;i<n;i++){
       int x;
       cin>>x;
       q.push(x);
   }
   for(int i=0;i<m;i++){
       cin>>e[i].bb>>e[i].cc;
   }
   sort(e,e+m,cmp);
   for(int i=0;i<m;i++){
       while(e[i].bb>0){
           if(e[i].cc<=q.top()){
               break;
           }
           q.push(e[i].cc);
           q.pop();
           e[i].bb--;
       }
   }
   int sum=0;
   for(int i=0;i<n;i++){
       sum+=q.top();
       q.pop();
   }
   cout<<sum<<endl;
}

    在写题的时候,总是只会写最简单的想法,不会如何优化,导致超时,以后要多写去练。

7.9

B题--Consecutive

在一个字符串中取一个字串,然后观察字串中是否有连续的两个相同的数字,进行输出。

开始的时候没有注意到时间,选择了两重循环来解,会超时。实际可以开两个数组,在开始时就处理。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 1e9 + 7;
int temp[300005];
int ans[300005];
signed main(){
    std::ios::sync_with_stdio(0);
    std::cin.tie(0);
    int n,q;
    int a,b;
    int sum=0;
    string s;
    cin>>n>>q;
    cin>>s;
    for(int i=0;i<s.size()-1;i++){
        if(s[i]==s[i+1]) temp[i]=1;
        else temp[i]=0;
        ans[i+1]=ans[i]+temp[i];
    }
    for(int i=0;i<q;i++){
        cin>>a>>b;
        cout<<ans[b-1]-ans[a-1]<<endl;
    }
    return 0;
}

A题--Sierpinski carpet

在比赛的时候读错了题意。以为只有中间的那个才会输出".",其余都是"#",所以交的几发都wa了。实际上,可以将其大的图案分成九宫格来看,每个九宫格的中心都会输出".",其余的都是”#“,然后再将四周的八个小格子,看成每个独立的小九宫格,将每一个小九宫格的中心变为”.",依此类推。

#include<bits/stdc++.h>
#include<math.h>
using namespace std;
#define int long long
signed main(){
    std::ios::sync_with_stdio(0);
    std::cin.tie(0);
    int n;
    char sum[735][735];
    cin>>n;
    //cout<<"pow="<<pow(3,n)<<endl;
    for(int i=1;i<=pow(3,n);i++){
        for(int j=1;j<=pow(3,n);j++){
            sum[i][j]='#';
            //cout<<sum[i][j];
        }
        //cout<<endl;
    }
    for(int k=1;k<=n;k++){
        for(int ia=1+pow(3,k-1);ia<=pow(3,n);ia+=pow(3,k)){
            for(int ib=1+pow(3,k-1);ib<=pow(3,n);ib+=pow(3,k)){
                for(int i=ia;i<ia+pow(3,k-1);i++){
                    for(int j=ib;j<ib+pow(3,k-1);j++){
                        sum[i][j]='.';
                    }
                }
            }
        }
    }
    for(int i=1;i<=pow(3,n);i++){
        for(int j=1;j<=pow(3,n);j++){
            cout<<sum[i][j];
            //cout<<'1';
        }
        cout<<endl;
    }
    //cout<<"pow="<<pow(3,n);
}

C题--Minimum Width

可以将数组进行排序,然后进行二分,查找最小值。

#include<bits/stdc++.h>
#include<math.h>
using namespace std;
#define int long long
int n,m;
int a[200005];
int l,r,mid;
int mm=0;
int temp(int x){
    int sum=-1,num=1;//sum的初值设为负数,保证可以消去第一个单词所带的空格,num相当于计数器,确定行数
    for(int i=1;i<=n;i++){
        if(sum+1+a[i]<=x){
            sum=sum+a[i]+1;
        }
        else{
            sum=a[i];
            num++;
        }
    }
    if(sum==-1) num--;//一行都没使用
    if(num<=m) return 1;
    else return 0;
}
signed main(){
    std::ios::sync_with_stdio(0);
    std::cin.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        mm=max(mm,a[i]);
    }
    l=mm-1;
    r=1e15+1;
    while(l+1<r){
        mid=(l+r)/2;
        if(temp(mid)==1){
            r=mid;
        }
        else{
            l=mid;
        }
    }
    cout<<r<<endl;
}

 D题--Printing Machine

一个物品在Ti秒进入打印机,在打印机上停留Di秒,打印机可以立即打印但每次打印后需要停留1秒后进行下一次工作。(相当于打印机工作一次需要一秒)

将每一个进入打印机时间相同的书同时压入vector中,然后将每一个结束时间跟打印机的工作时间相比,如果结束时间小于打印机的工作时间,则证明打印机无法打印该物体。

#include<bits/stdc++.h>
#include<math.h>
using namespace std;
#define int long long
int n,l,r;
int ans=0;
vector<pair<int,int>> sum;
signed main(){
    std::ios::sync_with_stdio(0);
    std::cin.tie(0);
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>l>>r;
        sum.emplace_back(l,r);
    }
    sort(sum.begin(),sum.end());
    int i=0;
    priority_queue<int,vector<int>,greater<int> > p;
    for(int t=0; ;t++){
        if(p.empty()){
            if(i==n) break;
            t=sum[i].first;
        }
        while(i<n&&t==sum[i].first){
            p.push(sum[i].first+sum[i].second);
            i++;
        }
        while(p.size()&&p.top()<t) p.pop();
        if(p.empty()==0){
            ans++;
            p.pop();
        }
    }
    cout<<ans<<endl;
}

二分训练--Music Notes

每一个音符都存在一段时间而且有先后顺序,所以可以使用二分查找。

#include<bits/stdc++.h>
using namespace std;
int n,q;
long long num[50005],aa,bb;
int main()
{
	cin>>n>>q;
	for(int i=0;i<n;i++)
	{
		cin>>aa;
		if(i==0) num[i]=aa;
		else num[i]=num[i-1]+aa;
	}
	while(q--)
	{
		cin>>bb;
		long long tmp=bb+1;
		int ans=lower_bound(num,num+n,tmp)-num+1;
		cout<<ans<<endl;
	}
	return 0;
}

二分训练--完全平方数

完全平方数从小到大一次递增,所以可以使用二分查找小于这个数中究竟有几个完全平方数,最后r-(l-1)即为答案。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 1e9 + 7;
int ff=1;
int temp(int x){
    int l=0,r=x;
    //cout<<"l="<<l<<endl;
    //cout<<"r="<<r<<endl;
    int mid;
    while(l<=r){
        mid=(l+r)/2;
        //cout<<"l="<<l<<endl;
        //cout<<"r="<<r<<endl;
        //cout<<"mid="<<mid<<endl;
        int kk=mid*mid;
        if(kk<=x){
            l=mid+1;
        }
        else{
            r=mid-1;
        }
    }
    return l;
}
signed main(){
    std::ios::sync_with_stdio(0);
    std::cin.tie(0);
    int a,b,mid,l,r,n;
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>a>>b;
            l=temp(a-1);
       //cout<<"l="<<l<<endl;
            r=temp(b);
            cout<<r-l<<endl;
       //cout<<"r="<<r<<endl;
        
    }
}

二分训练--跳石头

由于最短距离可以通过左右两端来回逼近,所以使用二分查找不断去逼近最短距离的最大值。

#include<bits/stdc++.h>
using namespace std;
int l,n,m;
vector<int> ve;
bool check(int x)
{
	int cnt=0;
	int now=0;
	for(int i=1;i<=n+1;)
	{
		if(ve[i]-ve[now]<x) 
		{
			cnt++;
			//now=i+1;
			i++;
		}
		else
		{
			now=i;
			i++;
		}
	}
	return cnt<=m;
}
int main()
{
	cin>>l>>n>>m;
	ve.push_back(0);
	for(int i=0;i<n;i++) 
	{
		int num;
		cin>>num;
		ve.push_back(num); 
	}
	ve.push_back(l); 
	int l=1,r=1000000000;
	while(l<r)
	{
	    int mid=(l+r+1)>>1;
	    if(check(mid))
	    {
	        l=mid;
	    }
	    else
	    {
	        r=mid-1;
	    }
	}
	cout<<l;
	return 0;
}

7.10

B题--抱歉

满足每个点都必须有两个跟他连接,所以n各点构成m个平面所需要最少的边n+m-2(n>=2);当所需平面数为一时,则不需要边;当只有一个点时,构成的m个平面所需边数位m-1;

#include<stdio.h>
int main(){
    long long n,m;
    scanf("%lld %lld",&n,&m);
    while(n!=0&&m!=0){
        long long sum;
        sum=n+m-2;
        if(m==1){
            sum=0;
        }
        else if(n==1){
            sum=m-1;
        }
        
        printf("%lld\n",sum);
        
        scanf("%lld %lld",&n,&m);
    }
    return 0;
}

C题--搬寝室

就是要让每次的左右手的差最小,比赛的时候没有将情况考虑清楚,所以交的几次全是错的。实际上,需要找出一个动态方程 dp[j] = min(dp[j-1], dp[j]+(a[2*i-2+j]-a[2*i+j-1])*(a[2*i-2+j]-a[2*i+j-1]));每次找到当前剩余的物品中,能让左右手差最小的数,然后依次累加。

还要注意的是他是每次输入,不是只输一次。

#include<bits/stdc++.h>
using namespace std;
//#define int long long
const int mod = 1e9 + 7;
int mm=INT_MAX;
signed main(){
    std::ios::sync_with_stdio(0);
    std::cin.tie(0);
    int n,k;
    int a[2005];
    long long f[2005][1005];
   // cin>>n>>k;
    while(cin>>n>>k){
        for(int i=1;i<=n;i++) cin>>a[i];
    sort(a+1,a+1+n);
    for(int i=0;i<=n;i++){
        for(int j=0;j<=k;j++){
            if(j==0) f[i][j]=0;
            else f[i][j]=mm;
        }
    }
    for(int i=2;i<=n;i++){
        for(int j=1;j<=min(k,i);j++){
            f[i][j]=min(f[i-1][j],f[i-2][j-1]+(a[i]-a[i-1])*(a[i]-a[i-1]));
        }
    }
    cout<<f[n][k]<<endl;}
}

I题--To 3

即是将每个数位上的数都对三进行求余,将每一个不能整除的数统计下来,并进行求和,如果求和后的数可以整出三,则整体可以,不能的话分类讨论。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 1e9 + 7;

signed main(){
    std::ios::sync_with_stdio(0);
    std::cin.tie(0);
    string s;
    cin>>s;
    int a[20];
    int sum=0;
    int j=0;
    int ll=0;
    int ee=0;
    for(int i=0;i<s.size();i++){
        int kk=s[i]-'0';
        if(kk%3!=0){
            a[++j]=kk%3;
            sum+=a[j];
            if(sum%3==0){
                j=0;
            }
        }
    }
    for(int i=1;i<=j;i++){
        if(a[i]%3==1) ll++;
        else if(a[i]%3==2) ee++;
    }
    int ans=sum%3;
    if(ans==0){
        cout<<'0'<<endl;
    }
    else if(ans==1){
        if(ll>=1) {
            //cout<<"jin1"<<endl;
            if(s.size()-ll==0){
                cout<<"-1"<<endl;
            }
            else {
                //cout<<"jin2"<<endl;
                cout<<'1'<<endl;}
        }
        else{
            if(s.size()-j==0){
                cout<<"-1"<<endl;
            }
            else {
                //cout<<"jin10"<<endl;
                cout<<j<<endl;}
        }
    }
    else{
        if(ee>=1){
            //cout<<s.size()<<' '<<j<<endl;
            if(s.size()-ee==0){
                cout<<"-1"<<endl;
            }
            else cout<<'1'<<endl;
        }
        else if(ee==0&&ll>=2){
            if(s.size()-j==0){
                cout<<"-1"<<endl;
            }
            else cout<<'2'<<endl;
        }
        else{
            if(s.size()-j==0){
                cout<<"-1"<<endl;
            }
            else cout<<s.size()-j<<endl;
        }
    }
}

二分训练--Greedy Gift Takers

二分查找一个循环,在这个循环内的每一头牛都能领到礼物,而循环之外的牛领不到任何礼物。

使用二分法不断逼近最后一头在循环内的牛。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 1e9 + 7;
int n,a[100005];
int b[100005];
bool temp(int x){
    for(int i=1;i<=x;i++){
        b[i]=0;
    }
    for(int i=1;i<=x;i++){
        b[a[i]]++;
    }
    for(int i=1;i<=x;i++){
        b[i]+=b[i-1];
        if(b[i]>=i) return true;
    }
    return false;
}

signed main(){
    std::ios::sync_with_stdio(0);
    std::cin.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++){
        int x;
        cin>>x;
        a[i]=n-x;
    }
    int l=1,r=n,mid;
    while(l<r){
        mid=(l+r)/2;
        if(temp(mid)) r=mid;
        else l=mid+1;
    }
    cout<<n-l<<endl;
}

 二分训练--Chocolate Eating

不断二分去查找最小幸福值,当大于等于最小幸福值的时候就进行除二,进入新的一天,继续进行累加以此类推。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 1e9 + 7;
int n,d;
int a[50005];
int ans[50005];
bool temp(int x){
    int cnt=0;
    int cc=1;
    for(int i=1;i<=d;i++){
        while(cnt<x&&cc<=n){
            cnt+=a[cc];
            ans[cc]=i;
            cc++;
        }
        if(cnt<x) return false;
        cnt/=2;
    }
    while(cc<=n){
        ans[cc]=d;
        cc++;
    }
    return true;
}
signed main(){
    std::ios::sync_with_stdio(0);
    std::cin.tie(0);
    cin>>n>>d;
    for(int i=1;i<=n;i++) cin>>a[i];
    int l=1,r=1e15;
    int mid;
    while(l<=r){
        mid=(l+r)/2;
        if(temp(mid)==true) l=mid+1;
        else r=mid-1;
    }
    cout<<l-1<<endl;
    temp(l-1);
    for(int i=1;i<=n;i++){
        cout<<ans[i]<<endl;
    }
}

7.11

二分训练--华华给月月准备礼物

二分查找木棍的最大值,看每根木棍可以分成多少个最大值的木棍,然后与所需要的杆子数进行比较,最后找出最大值。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 1e9 + 7;
int n,k;
int a[200005];
int mm=0;
bool temp(int x){
    int cnt=0;
    for(int i=1;i<=n;i++){
        cnt+=(a[i]/x);
    }
    //cout<<"cnt="<<cnt<<endl;
    if(cnt>=k) return true;
    else return false;
}
signed main(){
    std::ios::sync_with_stdio(0);
    std::cin.tie(0);
    cin>>n>>k;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        mm=max(mm,a[i]);
    }
    int l=1,r=mm;
    //cout<<mm<<endl;
    int mid;
    while(l<=r){
        mid=(l+r)/2;
        //cout<<"mid="<<mid<<endl;
        if(temp(mid)) l=mid+1;
        else r=mid-1;
    }
    cout<<r;
}

二分训练--扑克牌

二分查找。假设能凑成mid套牌,每一个不够mid的牌都会用j这个万能牌来代替,算出总共需要多少张万能牌,需要的万能牌的数目不能超过j的总数也不能超过mid(超过mid则证明有一套牌中使用了两次j,不合题意需要舍去)

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 1e9 + 7;
int n,m;
int c[55];
int temp(int x){
    int cnt=0;
    for(int i=1;i<=n;i++){
        int k=x-c[i];
        if(k>0) cnt+=k;
    }
    if(cnt<=m&&cnt<=x) return true;
    else return false;
}
signed main(){
    std::ios::sync_with_stdio(0);
    std::cin.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>c[i];
    }
    int l=0,r=1e9+10;
    int mid;
    while(l<=r){
        mid=(l+r)/2;
        if(temp(mid)) l=mid+1;
        else r=mid-1;
    }
    cout<<l-1<<endl;
}

二分训练--借教室

不仅需要用到二分还需要用到差分的思想,算出每天提供的教室与前一天提供的教室之间的数量差。然后计算差分的总和,当出现负数时则证明该天教室不够分。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 1e9 + 7;
int n,m;
int num[1000005],ans[1000005];
struct node{
    int d,str,end;
};
vector<node> ve;
bool temp(int x){
    int ans1[1000005];
    for(int i=1;i<=n;i++) ans1[i]=ans[i];
    for(int i=1;i<=x;i++){
        node nn=ve[i-1];
        ans1[nn.str]-=nn.d;
        ans1[nn.end+1]+=nn.d;
    }
    int sum=0;
    for(int i=1;i<=n;i++){
        sum+=ans1[i];
        if(sum<0) return false;
    }
    return true;
}
signed main(){
    std::ios::sync_with_stdio(0);
    std::cin.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>num[i];
        ans[i]=num[i]-num[i-1];
    }
    for(int i=1;i<=m;i++){
        node now;
        cin>>now.d>>now.str>>now.end;
        ve.push_back(now);
    }
    int l=0,r=m;
    int mid;
    while(l<=r){
        mid=(l+r)/2;
        if(temp(mid)) l=mid+1;
        else r=mid-1;
    }
    //cout<<l<<endl;
    if(l>=1&&l<=m){
        cout<<"-1"<<endl;
        cout<<l<<endl;
    }
    else cout<<'0'<<endl;
}

B题--Linear Approximation

 https://vjudge.net/problem/AtCoder-arc100_a/origin

相当于先将数组中的元素都减去自己的下标,然后将其重新排序,然后寻找中位数(相当于在数轴上寻找一个点,使其到各点的距离总和最小)

#include<bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
int a[200005];
signed main()
{
	int n;
	//int a[200005];
	cin>>n;
	for(int i=1;i<=n;i++){
	    int k;
	    cin>>k;
	    a[i]=k-i;
	}
	sort(a+1,a+1+n);
	int num=0;
	if(n==1) num=a[n];
	else num=(a[(n+1)/2]);
	int sum=0;
	for(int i=1;i<=n;i++){
	    sum+=abs(a[i]-num);
	}
	cout<<sum<<endl;
	
}

C题--Minimization

https://vjudge.net/problem/AtCoder-arc099_a/origin

 和最小数1出现的位置无关,之与N和K有关,比赛的时候没有考虑到k,只考虑了N。

#include<bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
signed main()
{
	int n,k;
	int a[100005];
	cin>>n>>k;
	for(int i=1;i<=n;i++){
	    cin>>a[i];
	}
	int l=0,cnt=0;
	while(l<n){
	    if(l==0) l+=k;
	    else l+=k-1;
	    cnt++;
	}
	cout<<cnt<<endl;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值