901DIV2 (A~D)

901DIV2 A~D

A:

  • 大于等于\(a-1\)的贡献都是a-1.
void solve(){
    int ans=0;
    int a,b,n;
    cin>>a>>b>>n;
    ans+=b;
    for(int i=1;i<=n;i++){
        int x; cin>>x;
        if(x>=a) x=a-1;
        ans+=x;
    }
    cout<<ans<<"\n";
 
}

B:
因为n,m只有50,可以考虑模拟。

  • 对于k=1000000和k=1000次的结果,一定是一样的。
  • 注意模拟的次数一定和k的奇偶性质一样。
void solve(){
   int ans=0;
   int n,m,k;
   cin>>n>>m>>k;
   for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=m;i++){
        cin>>b[i];
    }
    int flag=0;
    if(k>10000){
        if(k&1) k=10001;
        else k=1000;
    }
    int now=1;
    while(k--){
        now^=1;
        if(now==0){
            int num1,mina1;
            num1=0; mina1=1e12;
            for(int i=1;i<=n;i++){
                if(a[i]<mina1){
                    mina1=a[i];
                    num1=i;
                }
            }
            int num2,maxa1;
            num2=0; maxa1=0;
            for(int i=1;i<=m;i++){
                if(b[i]>maxa1) {
                    num2=i;
                    maxa1=b[i];
                }
            }
 
            if(mina1<maxa1){
                swap(a[num1],b[num2]);
            }
        }
        else{
            int num1,mina1;
            num1=0; mina1=1e12;
            for(int i=1;i<=m;i++){
                if(b[i]<mina1){
                    mina1=b[i];
                    num1=i;
                }
            }
            int num2,maxa1;
            num2=0; maxa1=0;
            for(int i=1;i<=n;i++){
                if(a[i]>maxa1) {
                    num2=i;
                    maxa1=a[i];
                }
            }
 
            if(mina1<maxa1){
 
                swap(b[num1],a[num2]);
            }
        }
    }
    for(int i=1;i<=n;i++) ans+=a[i];
        cout<<ans<<"\n";
}

C:
首先判断一下可不可以:

  • 暴力判断:用double存储结果之后,乘以200个2看中间是否会出现整数。
    错误的,因为浮点数会出现很不可预料的误差。出现了这样的情况:

    0.2*2:(去掉整数部分)
    0.4
    0.8
    0.6
    0.2
    0.4
    0.8
    0.6
    ...
    0.6
    0.20000001
    

    所以不用浮点数的计算来解决判断问题。

  • 问题转换为:
    给定\(x,y\).现在有\(x/y\)的结果,问这个结果经过无数次的\(*2\)之后,是否会转换为一个整数?

    • 解决方法:\(y/=gcd(x,y)\).
      然后判断y是不是2的倍数,如果是,就可以。不是就不可以。

    因为通过乘以2变为整数,分母的众多因子,和2有关系的可以通过乘以2不断消掉,其他的如果出现过类似于\(3,5,7\)这种,必须由分子自行消除掉才可以。

  • 求解次数问题:

     while(1){
            int M=t;
            need[now]=M*m;//整数部分是几 说明需要几个 几个不是几刀捏。
            t-=M;
            t*=2;
            now++;
            if(t==0) break;
        }
        for(int i=1;i<=200;i++){
            ans+=cal(i,need[i]);
        }
    
    
    
    
    int cal(int now,int need){
        // cout<<now<<" "<<need<<endl;
        if(need==0) return 0;
        int sum=0;
        
        if(now==1){
            if(hav[now]>need) {
                hav[now]-=need;
                return 0;
            }
            need-=hav[now];
            hav[now]=0;
    
            if(need%2==0){
                return need/2;
            }
            else {
                hav[need]++;
                return (need+1)/2;
            }
        }
        else {
            if(hav[now]>need) {
                hav[now]-=need;
                return 0;
            }
            need-=hav[now];
            hav[now]=0;
    
            if(need%2==0){
                sum+=need/2;
            }
            else {
                hav[now]++;
                sum+=(need+1)/2;
            }
            sum+=cal(now-1,(need+1)/2);
        }
        return sum;
    }
    

D:

思路:
有一个结论是,当前mex为x,最终是变为0的,有很多种方式可以到达0,现在如果想要转换为y,也有很多种方式,但是一旦我选择把\(v\)删除,并且v没有被全部删除,我下次一定删除的还是v。
根据贪心的原理,如果v不是最优秀的,我没必要弄v,如果是最优秀的,我就需要一直处理v。

有很多种方式将\(mex\)从v转变为0.最后转变为图论最短路问题。
把每一种方式、路径都处理出来,跑dijikstra即可。

void solve(){
	int n; cin>>n;
	for(int i=0;i<=n;i++){
		vis[i]=0;
		ans[i]=-1;
		V[i]=0;
	}
	for(int i=0;i<=n;i++){
		for(int j=0;j<=n;j++){
			dis[i][j]=INF;
		}
	}
	for(int i=1;i<=n;i++){
		cin>>a[i];
		if(a[i]<=n+1) vis[a[i]]++;
	}
	int s=-1;
	for(int i=0;i<=n;i++){
		if(vis[i]==0){
			s=i; break;
		}
	}
	if(s==0){
		cout<<"0\n"; return ;
	}	
	for(int i=s;i>=0;i--){
		for(int j=i-1;j>=0;j--){
			dis[i][j]=(vis[j]-1)*i+j;
		}
	}

	priority_queue< pair<int,int> ,vector<pair<int,int>>, greater<pair<int,int>> >q;
	q.push({0,s});
	while(!q.empty()){
		pair<int,int> tsk=q.top();
		q.pop();
		int u=tsk.second;
		if(V[u]) continue;
		V[u]=1;
		ans[u]=tsk.first;
		for(int j=0;j<u;j++){
			int now=ans[u]+dis[u][j];
			if(ans[j]==-1 || ans[j]>now){
				ans[j]=now;
				q.push({ans[j],j});
			}
		}
	}
	cout<<ans[0]<<"\n";

}

posted @ 2023-10-01 10:21  橘赴亦梦人ω  阅读(6)  评论(0编辑  收藏  举报