Simple 杂题练手记

Problem 1 世界上最可爱的珂朵莉

时间限制:C/C++ 1秒,空间限制:C/C++ 65536Kios

题目描述
我永远喜欢珂朵莉~!
有两个长为n的序列a[i]与b[i]
你能够把任意很少于x个a序列中的数变成y
你能够把全部序列b中的数减去一个非负数t
你能够把a序列和b序列分别任意打乱
要求对于1 <= i <= n知足a[i] >= b[i]
求t的最小值c++

输入描述:
第一行三个数n,x,y
以后一行n个数表示a序列
以后一行n个数表示b序列测试

输出描述
一行一个非负数表示答案
输入示例1
输入
10 0 233333
227849 218610 5732 128584 21857 183426 199367 211615 91725 110029
8064826 14174520 10263202 9863592 592727 7376631 5733314 1062933 12458325 15046167
输出
14818318优化

数据范围
对于100%的数据,0 <= n <= 200000 , 0 <= x,y <= 2000000000,0<=a[i],b[i]<=2000000000
---------------------spa

分析:
若是没有1操做将a序列中的数变成y,则改题只须要将a和b分别排序,而后找出对应位置的最大差值便可。
如今有操做1,则先将a序列排好序,而后从小到大将a序列中的值与y依次比较,若是小于y,就更换。再从新对变换后的a序列排序,将a序列和b序列依次比较,寻找相应位置上最大的差值即为全部答案!code

#include<bits/stdc++.h>
using namespace std;

int A[200010], B[200010];
 
int main()
{
    int n, x, y;
    scanf("%d%d%d", &n, &x, &y);
    for(int i = 0; i < n; i++) 
        scanf("%d", &A[i]);
    for(int i = 0; i < n; i++) 
        scanf("%d", &B[i]);
    sort(A, A+n);
    sort(B, B+n);
    for(int i = 0; i < n; i++)
    {
        if(x!=0 && A[i] < y) 
        {
            A[i] = y, x--;
        }
        if(x <= 0 || A[i] > y) break;
    }
    sort(A, A+n);
    int Ans = 0;
    for(int i = 0; i < n; i++) 
        Ans = max(Ans, B[i]-A[i]);
    printf("%d\n", Ans);
    return 0;
}

电池的寿命

总时间限制: 1000ms 内存限制: 65536kB排序

问题描述

小S新买了一个掌上游戏机,这个游戏机由两节5号电池供电。为了保证可以长时间玩游戏,他买了不少5号电池,这些电池的生产商不一样,质量也有差别,于是使用寿命也有所不一样,有的能使用5个小时,有的可能就只能使用3个小时。显然若是他只有两个电池一个能用5小时一个能用3小时,那么他只能玩3个小时的游戏,有一个电池剩下的电量没法使用,可是若是他有更多的电池,就能够更加充分地利用它们,好比他有三个电池分别能用三、三、5小时,他能够先使用两节能用3个小时的电池,使用半个小时后再把其中一个换成能使用5个小时的电池,两个半小时后再把剩下的一节电池换成刚才换下的电池(那个电池还能用2.5个小时),这样总共就可使用5.5个小时,没有一点浪费。
如今已知电池的数量和电池可以使用的时间,请你找一种方案使得使用时间尽量的长。游戏

输入格式

输入包含多组数据。
输入第一行,一个整数T,表示数据的组数。
接下来每组数据包括两行,第一行是一个整数N (2 ≤ N ≤ 1000),表示电池的数目,第二行是N个正整数表示电池能使用的时间。ip

输出格式

对每组数据输出一行,表示电池能使用的时间,保留到小数点后1位。
样例输入
2
2
3 5
3
3 3 5
样例输出
3.0
5.5内存

问题分析

初看之下,本题感受没有什么很好的思路,但应该有贪心的办法。
因为每枚电池的使用时间不一样,而咱们又要减小浪费才能使全部电池加起来用得最久,不难发现:若是咱们把使用时间最长的电池比喻成第一战队,其余电池比喻成第二战队,使用时间就是战斗力,
每次从拿电池使用时间最长的和另外战队里电池使用时间最长的相互战斗消耗1个战斗力;而且在每次战斗后,从新调整战队的分配状况(最大电池容量可能发生了变化)。

事实上,你会发现:其实对于每一组数据只要判断最大的那个数是否是比其他的数的和都要大,若是成立的话那固然就是剩下的全部电池与最大的电池车轮战,最大值为n-1个数的和,若是不成立的话那么最大就是n个数的和的一半,也就是说电池是必定能够所有用完的。讲一下简单的证实过程,每次先对N个数进行排序,而后最大电池每次与其他电池PK一小时,如此进行下去最后必然是三种状况中的一种即(2 1 1)(1 1)(1 1 1),这三种状况都是能够用完的,因此电池一定会所有用完。

#include <bits/stdc++.h>
using namespace std;
 
int main()
{
    int n,T;
    int buf[1000];
    double ans;
    cin>>T;
    for(int t=1;t<=T;++t)
    {
        ans=0;
        for(int i=0;i<n;i++){
            scanf("%d", &buf[i]);
            ans+=buf[i];
        }
        sort(buf,buf+n);
        if(buf[n-1]>ans-buf[n-1])
            ans=ans-buf[n-1];
        else
            ans=ans*1.0/2;
       printf("%.1f\n", ans);
    }
    return 0;
}

CJOJ P1236 - 指数序列求和

Description
\(1^b+2^b+…+a^b\) 的和除以10000的余数。

Input
第一行包含一个正整数N,表示有N组测试数据
接下来N行每行包含两个正整数a和b

Output
输出共N行,每行一个对应的答案

Sample Input
1
2 3

Sample Output
9

Hint
数据范围:
对于30%数据 \(n≤10,a,b≤1000\)
对于100%数据 \(n≤100,a,b≤10^9\)

分析
快速幂+同类余数优化
暴力分30分不用解析了,就算你用了快速幂,for循环一遍,仍是30分。
for循环的时候循环枚举到a是必定不可能的,咱们知道在咱们取膜的时候ac%b=a%bc%b,因此咱们利用这个原理,由于是挨着快速乘,他们取膜之后的数也必定是连着的,分析以后就会发现a^b和(a+mod)^b对答案的影响是同样的,证实是显然的。
因此说咱们对于任意 i^b 均可以写成 (i%mod)^b ,因为 mod 10000,模数只有一万能够推算出mod10000相同的数,分在一组,好比2333和23333和233333就分在一组。
而后,这一组有多少个数,我就把这个组的数快速幂求出b次方而后乘组中元素个数就好了(详情看代码)。

#include<bits/stdc++.h>
using namespace std;
int mod=10000;

int Pow(int x,int y)
{
    int base=x, cnt=1;
    while(y>0)
    {
        if(y%2==1)
            cnt=cnt*base%mod;
        base=base*base%mod;
        y=y>>1;
    }
    return cnt;
}

int main()
{
    int n,a,b,ans;
    cin>>n;
    while(n>0)
    {
        n=n-1, ans=0;
        cin>>a>>b;
        int k=min(mod-1,a);
        for(int i=1;i<=k;++i)
            //1~a范围内余数同为i的一共有 1+(a-i)/mod 组,统计余数相同的这组数的幂次方 
            ans=(ans+(1+(a-i)/mod)*Pow(i,b)%mod)%mod;
            
        cout<<ans<<endl;
    }
    return 0;
}

化学反应

Description

有 N 种不一样的物质,每种物质有两个属性——“能量”和“活度”。 N 种中的任意两种物质均可以发生反应;反应放热为两种物质的“能量”之差加一再乘上“活度”的较大值。
换句话说,设第 i 种物质的能量和活度分别为 Ai 和 Bi,则 i 和 j 反应的放热为 (| Ai-Aj |+1) * max(Bi, Bj)
如今你须要选出两种物质,最小化它们反应放出的热量。这个最小值是多少?

Input

本题包含多组测试数据,第一行为测试数据组数 T。
对于每组数据:
第一行一个正整数 N,表示物质种类数。
接下来 N 行每行两个正整数 Ai、 Bi,表示第 i 种物质的“能量”和“活度”。

Output

输出一行一个正整数,最小放热。 注意这个数可能须要 64 位整型来存储。

Sample Input

1
7
19 5
5 6
1 2
8 4
25 10
12 3
9 6

Sample Output

12

数据范围:

对于 40%的数据,N<=1000,T<=5
对于另外 20%的数据,N<=10^5,Ai、 Bi<=10^3,T=1
对于 100%的数据,N<=10^5,Ai、 Bi<=10^9,T<=40

分析:
40%的数据 $ N<=1000,O(n^2)$ 的复杂度将任意两种物质进行两两反应,反应的最小值即为所求答案。复杂度 \(O(T*n^2)\)
对于另外20%的数据,\(N<=10^5\),且 \(Ai Bi<=10^3,T=1\),能够发现物品的种类数不少,可是能量和活度的值域很小。若是咱们对每种物质按照活度进行从小到大排序,本问题的关键在于找到 Bj<=Bi,且 | Aj-Ai |最小(即能量最接近i物质)的j物质
因为 $ Bi<=10^3$,所以开vector值域活度的桶,将活度相同的物质丢进同一类桶中,从小到大排序后对于每个Bi,查找B1~Bi的桶内全部的元素并让它们相互反应,最小的 | Ai-Aj |即为在两种物质活度最大值为Bi时反应的最小热量,
最后取整个反应里的最小值即为所求的答案。复杂度 \(O(T*10^3*n)\)
对于100%的数据,$ Ai Bi<=10^9$ 从新回到本题的关键问题,在于对于活度为Bi的物质,要找到 Bj<=Bi,且 | Aj-Ai |最小(即能量最接近i物质)的j物质。
所以首先仍是按照活度从小到大进行排序,而后根据排序后物质的活度 Bi 从小到大进行枚举,对于每个 Bi 查找前面已经枚举完成的 j 物质(一定有Bj<=Bi),找到能量值刚好大于等于Ai的Aj,即为两种物质活度最大值为Bi时反应的最小热量,
接下来考虑如何查找 i 物质以前,能量值与 i 最接近的物质j,若是暴力去逐个比较,那么最坏的复杂度依然会达到 \(O(n^2)\)。最快的查找方法固然是二分查找了,要想使用二分查找那么i以前的物质能量属性 Aj 应当维护一个有序序列。
怎么维护物质i以前的能量属性Aj有序呢?
方法①: 插入排序
方法②: Set
最终时间复杂度 $ O(T*nlogn) $ ,Set常数巨大,极可能会被卡掉

#include <cstdio>
#include <iostream>
#include <set>
#include <algorithm> 
using namespace std; 
#define l_b lower_bound
#define w1 first
#define w2 second
#define m_p make_pair
#define LL long long 
typedef pair<int,int> PII;
const int maxn=100005;
set<int> f;
set<int>::iterator lsh;
int T,N;
int a[maxn],b[maxn];
PII ls[maxn]; 
int main()
{    
    scanf("%d",&T);    
    for (int gb=1;gb<=T;gb++)    
    {        
        scanf("%d",&N);        
        for (int i=1;i<=N;i++) scanf("%d %d",&a[i],&b[i]);        
        for (int i=1;i<=N;i++) ls[i]=m_p(b[i],a[i]);        
        sort(ls+1,ls+N+1);        
        for (int i=1;i<=N;i++) a[i]=ls[i].w2,b[i]=ls[i].w1;        
        LL minc=1000000000;        
        minc=(LL)minc*minc;        
        f.clear();        
        for (int i=1;i<=N;i++)        
        {            
            if (i!=1)            // i不是第一个,去寻找i前面活度Bj<=Bi,且能量最接近ai的物质j 
            {                
                lsh=f.l_b(a[i]);  // 寻找i前面能量值第一个大于等于a[i]的位置              
                if (lsh!=f.end())                    
                    minc=min(minc,(LL)b[i]*((*lsh)-a[i]+1));                
                if (lsh!=f.begin())    // 寻找i前面能量值刚好小于a[i]的位置               
                {                    
                    --lsh;                    
                    minc=min(minc,(LL)b[i]*(a[i]-(*lsh)+1));                
                }            
            }            
            f.insert(a[i]);        
        }        
        cout<<minc<<endl;    
    }    
    return 0;
}
相关文章
相关标签/搜索