3 条题解

  • 1
    @ 2025-11-16 23:58:48

    思路就是先前n+m个按规则分配,你会发现你少一个人那就是把第n+m+1那个人加上把第i个人删了就行,所以要预处理n+m个人,如果大家判断第i个是程序员或者测试员,然后直接删了他,把第n+m+1这个人顶替他的位置其实就漏了一种情况了,就是n个程序员选出来了了,然后后面有一个人适合做程序员也只能做测试员了,然后你删了一个程序员,是不是可以将原来的这个测试员派到程序员那里,细节1只有这种情况,那就好处理了,只要判断程序员人数够时后面第一个适合做程序员这个人的位置,和测试员人数够时后面第一个适合做测试员这个人的位置,有一个错误就是n或者m本来就是0时就不用找了,所以特判n或者m是0的情况,是0 就让他是-1,然后找找,(应该会)再开2个数组,用来标记第i个人是程序员还是测试员,然后就可以遍历了如果这个人是程序员而且存在后面适合当程序员的但是没有当上程序员的人k那就是把第i个人的值减了,再减去第k个人当测试员的值,加上第k个人当程序员的值然后把第n+m+1这个人当测试员的值,(简单来说就是把第i个人删了,把第k个人换成程序员然后把第n+m+1个人当测试员加上去就行了),第i个人是测试员操作一样。

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    void sll()
    {
    int n,m;
    cin>>n>>m;
    int arr[n+m+10]={0};
    int brr[n+m+10]={0};
    int gs=m+n+1;
    for(int i=1;i<=gs;i++)
    {
        cin>>arr[i];
    }
    for(int i=1;i<=gs;i++)
    {
        cin>>brr[i];
    }
    if(n==0)
    {
        n=-1;
    }
    if(m==0)
    {
        m=-1;
    }
    int t=0;
    int pp1[n+m+10]={0};
    int pp2[n+m+10]={0};
    int kk1=0;
    int kk2=0;
    for(int i=1;i<gs;i++)
    {
        if(n==0&&arr[i]>brr[i]&&kk1==0)
        {
            kk1=i;
        }
        if(m==0&&brr[i]>arr[i]&&kk2==0)
        {
            kk2=i;
        }
        if(arr[i]>brr[i]&&n>0)
        {
            n--;
            t+=arr[i];
            pp1[i]=1;
        }
        else if(m>0) 
        {
            m--;
            t+=brr[i];
            pp2[i]=1;
        }
        else 
        {
            pp1[i]=1;
            n--;
            t+=arr[i];
        }
    }
    int a=arr[gs];
    int b=brr[gs];
    for(int i=1;i<gs;i++)
    {
        if(pp1[i]==1)
        {
            if(kk1==0)
            {
            cout<<t-arr[i]+a<<' ';
            }
            else 
            {
                cout<<t-arr[i]-brr[kk1]+arr[kk1]+b<<' ';
            }
        }
        else 
        {
            if(kk2==0)
            {
            cout<<t-brr[i]+b<<' ';
            }
            else 
            {
                cout<<t-brr[i]-arr[kk2]+brr[kk2]+a<<' ';
            }
        }
    }
    cout<<t<<'\n';
    }
    signed main() {
        ios::sync_with_stdio(0);
        cout.tie(0),cin.tie(0);
        int cs=1;
        cin>>cs;
        while(cs--)
        {
            sll();
        }
        return 0;
    }
    
    • 0
      @ 2025-11-16 23:43:24
      #include <bits/stdc++.h>
      using namespace std;
      #define rep(i, l, r) for (int i = l; i <= r; i++)
      #define pii pair<int, int>
      #define int long long
      #define pb push_back
      #define se second
      #define fi first
      #define endl '\n'
      double pi = acos(-1);
      const int N = 1e6, mod = 1e9+7, inf = 1e18 + 5;
      int fpow(int a,int b){
          int res = 1;
          while(b){
              if(b&1) res = res * a % mod;
              a = a * a % mod;
              b >>= 1;
          }
          return res % mod;
      }
      void solve() {
          int n, m; cin >> n >> m; 
          vector<int> a(n + m + 2), b(n + m + 2);  
          for (int i = 1; i <= n + m + 1; i ++) cin >> a[i];
          for (int i = 1; i <= n + m + 1; i ++) cin >> b[i];
          int posa = n + m + 1; 
          int posb = n + m + 1; 
          int cnta = 1, cntb = 1;         
          int suma = 0, sumb = 0;              
          vector<bool> vis(n + m + 2, false); 
      
          for(int i = 1; i <= n + m; i++){
              if(a[i] > b[i]){  
                  if(cnta <= n){  
                      cnta ++;
                      suma += a[i];
                      vis[i] = true; 
                  } else { 
                      if(posa == n + m + 1) posa = i;  
                      if(cntb <= m){  
                          sumb += b[i]; 
                          cntb ++;
                      }
                  }
              } else {  
                  if(cntb <= m){ 
                      cntb ++;
                      sumb += b[i];
                  } else { 
                      if(posb == n + m + 1) posb = i;  
                      if(cnta <= n){ 
                          suma += a[i]; 
                          cnta ++; 
                          vis[i] = true;
                      }
                  }
              }
          }
          for(int i = 1; i <= n + m; i++){
              if(vis[i]){ 
                  int ans = suma + sumb - a[i] + a[posa];  
                  if(posa != n + m + 1){  
                      ans += b[posb] - b[posa];
                  }
                  cout << ans << ' ';
              }else{  
                  int ans = suma + sumb - b[i] + b[posb]; 
                  if (posb != n + m + 1){ 
                      ans += a[posa] - a[posb];
                  }
                  cout << ans << ' ';			
              }
          }
          cout << suma + sumb << endl;
      }
      signed main() {
          ios::sync_with_stdio(0); 
          cin.tie(0);
          cout.tie(0);
          int T = 1;
          cin >> T; 
          while (T--)
              solve();
          return 0;
      }
      
      • 0
        @ 2025-11-15 19:46:21

        第一部分:暴力思路与职位固定性分析

        暴力思路

        我们首先一起来想一个暴力思路。

        暴力怎么做?很简单,依次枚举每一个面试者 ii,如果 ii 没有来面试,那么公司对于剩下的人一个一个按照规则聘用,公司的能力值是多少。时间复杂度 O((n+m)2)O((n + m)^2)

        职位固定性观察

        在暴力的过程中可以观察到,总有那么一些面试者,无论谁不来面试,只要不来面试的不是这个人,这个人的职位就是固定的,一定是程序员和测试员中的一个。

        职位非固定条件分析

        现在我们来考虑什么人的职位不是固定的。在考虑这个之前,我们先来考虑对于第 ii 个面试者,如果面试者 jj 来与不来能够影响面试者 ii 的职位,jjii 应该满足什么样的关系。

        必要条件

        首先,我们要知道面试是按照面试者来的顺序的。如果 jjii 之后才来,也即 j>ij > i,那么 jj 来与不来都是不会影响 ii 的职位的,毕竟 ii 之前的人是没有变的,面试到 ii 时的状态也是没有变的。

        因此,我们得到了一个结论:如果一个面试者 jj 来与不来能够影响面试者 ii 所处职位,那么 jjii 之前,也就是 j<ij < i

        充分必要条件分析

        我们假设 ai>bia_i > b_i。如果 j<ij < i 并且 jj 没来,然后 ii 的职位改变了,显而易见 ii 只能是从测试员变成程序员。很好理解,原来 ii 是可以被聘为程序员的,但是因为程序员人满了,只能屈才当下测试员了。现在程序员走掉一个,空出来一个位置,那么 ii 肯定又能当回程序员了。

        如果 jj 不来能够使 ii 从测试员变成程序员,我们得到了如下三重判断:

        • aj>bja_j > b_j
        • ii 刚好是第 n+1n+1 个满足 ai>bia_i > b_i 的。jj 走掉之后 ii 变成了第 nn 个,所以转职了。

        反之亦然。

        第二部分:岗位分配与能力值计算

        关键变量记录

        接下来的事情就很好办了。记录一下第 n+1n+1 个满足 ai>bia_i > b_iii 和第 m+1m+1 个满足 bi>aib_i > a_iii,分别记为 time3time4(胡乱取的变量名),容易发现 time3time4 只会有一个有值。很好理解,如果 time3time4 都有值,那么至少有 n+1n+1 个满足 ax>bxa_x > b_xxxm+1m+1 个满足 by>ayb_y > a_yyy,那么至少有 n+m+2n+m+2 个面试者,与题目条件“总共有 n+m+1n+m+1 个面试者”矛盾。

        初始能力值计算

        接下来就是对答案的处理。首先记录一个 ans 表示如果录取了所有面试者,公司的能力值。其中,对于第 n+m+1n+m+1 个面试者,如果 ai>bia_i > b_i,其是测试员;反之则是程序员。这样设表示其被强制转职了。

        枚举处理每个面试者

        11n+m+1n+m+1 枚举每一个面试者 ii

        • 如果 ai>bia_i > b_i,并且满足 time3 有值且 i<time3i < \text{time3},说明面试者 time3 的职位改变了,输出:ans - aia_i + atime3a​_{time3} - btime3b_{time3},反之,ii 一定是一个测试员,输出:ans-bib_i
        • 如果 bi>aib_i > a_i 也是同样的道理(对称处理)。
        #include<bits/stdc++.h>
        using namespace std;
        long long a[2001000], b[2001000];
        int main()
        {
        	int t;
        	scanf("%d", &t);
        	for (int i = 1; i <= t; i++)
        	{
        		int n, m;
        		scanf("%d%d", &n, &m);
        		for (int i = 1; i <= n + m + 1; i++)
        		{
        			scanf("%lld", &a[i]);
        		}
        		for (int i = 1; i <= n + m + 1; i++)
        		{
        			scanf("%lld", &b[i]);
        		}
        		int time1 = 0, time2 = 0, time3 = 2e5 + 100, time4 = 2e5 + 100;
        		long long ans = 0;
        		for (int i = 1; i <= n + m + 1; i++)
        		{
        			if (a[i] > b[i])
        			{
        				if (time1 < n)
        				{
        					time1++;
        					ans += a[i];
        				}
        				else
        				{
        					ans += b[i];
        					if (time1 == n)
        					{
        						time1++;
        					}
        				}
        			}
        			else if (a[i] < b[i])
        			{
        				if (time2 < m)
        				{
        					time2++;
        					ans += b[i];
        				}
        				else
        				{
        					ans += a[i];
        					if (time2 == m)
        					{
        						time2++;
        					}
        				}
        			}
        			if (time1 == n + 1 && time3 == 2e5 + 100)
        			{
        				time3 = i;
        			}
        			if (time2 == m + 1 && time4 == 2e5 + 100)
        			{
        				time4 = i;
        			}
        		}
        		//printf("%d %d\n", time3, time4);
        		long long ans1;
        		for (int i = 1; i <= m + n + 1; i++)
        		{
        			ans1 = ans;
        			if (a[i] > b[i])
        			{
        				if (i < time3)
        				{
        					ans1 -= a[i];
        					ans1 = ans1 + a[time3] - b[time3];
        				}
        				else
        				{
        					ans1 -= b[i];
        				}
        			}
        			if (a[i] < b[i])
        			{
        				if (i < time4)
        				{
        					ans1 -= b[i];
        					ans1 = ans1 + b[time4] - a[time4];
        				}
        				else
        				{
        					ans1 -= a[i];
        				}
        			}
        			printf("%lld ", ans1);
        		}
        		printf("\n");
        	}
        	return 0;
        }
        
        • 1

        信息

        ID
        1204
        时间
        1000ms
        内存
        256MiB
        难度
        10
        标签
        递交数
        11
        已通过
        1
        上传者