其他分享
首页 > 其他分享> > 9.13 Test——NOIP模拟赛

9.13 Test——NOIP模拟赛

作者:互联网

T1:backpack

NYG的背包

 

【问题描述】

NYG有一个神奇的背包,每放进去一个物品,背包的体积就会变大。 

也就是说,每放进一个物品,背包会被占用一定的体积,但是紧接着背包的总体积又 会增大一定的值(注意是在放入物品后背包总体积才增大)。
NYG发觉这个背包十分好用,于是不由自主地想到了一个问题。
现在给出背包初始容量V 以及n个物品,每一个物品两个值a, b,分别表示物品所占体积 和放入背包后背包增大的体积。
NYG想知道能否把所有物品装进去? 因为NYG比较老实,这么简单的问题自然装作不会做的样子。 于是他来请教你。

 

【输入格式】

从文件backpack.in中读入数据
输入文件包含多组数据。
第一行一个数扔表示数据组数。
对于每组数据,第一行两个数n, h,接下来扮行每行两个数a, b表示物品所占体积和放入背包后背包增大的体积。


【输出格式】

输出到文件backpack.out中
对于每一组数据,如果能把所有物品装进去,输出"Yes",否则输出"No"(不包含引号)


【样例输入1】

3 5
3 1
4 8
8 3


【样例输出1】

Yes


【样例输入2】

3
7 9269
21366 1233
7178 23155
16679 23729
15062 28427
939 6782
24224 9306
22778 13606
5 22367
17444 5442
16452 30236
14893 24220
31511 13634
4380 29422
7 18700
25935 4589
24962 9571
26897 14982
20822 2380
21103 12648
32006 22912
23367 20674


【样例输出2】

Yes
Yes
No


【数据规模和约定】

对于1~4个测试点,T=10, 1≤n≤9, 1≤V≤100000, 0≤a,b≤100000
对于5∼8个测试点,T=20, 1≤n≤1000, 1≤V≤100000, 0≤a,b≤100000
对于9∼12个测试点,T=5, 1≤n≤100000, 1≤V≤1000, 0≤a,b≤1000
对于13~16个测试点,T=500, 1≤n≤1000, 1≤V≤100000, 0≤a,b≤100000
对于17∼20个测试点,T=8, 1≤n≤50000, 1≤V≤100000, 0≤a,b≤100000

 

解析:

   $Maxmercer$上课时讲的例题,记得当时我和周围的人讨论了很久,下课我还找他问过一下的来着

  思路显然是贪心

  肯定需要把$a<b$的先用了,才可能搞得定$a>b$的

  对于$a<b$的部分,肯定是先打$a$较小的,这样才可以尽力避免出现负数的情况

  问题在于$a \leqslant b$的部分应该怎样安排,这也是当时我们上课时讨论的中心

  这一部分思路很巧妙

  反向地看这个放东西的部分,相当于是所需空间为$b$,能增大$a$的容量,$a>b$,这样的话就变成了和前面的情况了

  因此这一部分只需要按$b$从大到小排序,再顺次扫过去就可以了

 代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 100004;

inline int read()
{
    int ret, f=1;
    char c;
    while((c=getchar())&&(c<'0'||c>'9'))if(c=='-')f=-1;
    ret=c-'0';
    while((c=getchar())&&(c>='0'&&c<='9'))ret = (ret<<3)+(ret<<1)+c-'0';
    return ret*f;
}

int T, n, s, cnt1, cnt2;
struct thi{
    ll a, b;
}t[maxn], f[maxn];

bool cmp1(thi x, thi y)
{
    return x.a < y.a;
}

bool cmp2(thi x, thi y)
{
    return x.b > y.b;
}

int main()
{
    freopen("backpack.in", "r", stdin);
    freopen("backpack.out", "w", stdout);
    T = read();
    while(T--)
    {
        n = read();s = read();
        cnt1 = cnt2 = 0;    
        for(int i = 1; i <= n; ++i)
        {
            ll x = 1LL * read(), y = 1LL * read();
            if(y > x)
                t[++cnt1] = (thi){x, y};
            else
                f[++cnt2] = (thi){x, y};
        }
        sort(t + 1, t + cnt1 + 1, cmp1);
        ll now = 1LL * s;    
        bool fl = 0;    
        for(int i = 1; i <= cnt1; ++i)
        {
            now -= t[i].a;
            if(now < 0)
            {
                fl = 1;
                break;
            }
            now += t[i].b;    
        }
        if(!fl)
        {
            sort(f + 1, f + cnt2 + 1, cmp2);
            for(int i = 1; i <= cnt2; ++i)
            {
                now -= f[i].a;
                if(now < 0)
                {
                    fl = 1;
                    break;
                }
                now += f[i].b;    
            }
        }
        printf("%s\n", fl? "No": "Yes");
    }
    return 0;
}
backpack

 

T2:point

NYG的动态数点

 

【问题描述】

NYG是一个善于思考的好学生。
于是NYG想往他的背包中放序列。
某一天NYG得到了一个长度为n的序列{ai}。然后NYG说,如果对于一段区间[L, R],存在L ≤ k ≤ R使得∀i∈[L, R]都有a| ai,我们认为它有价值,价值为R − L(若不满足条件则没有价值)。
现在NYG想知道所有区间中价值最大为多少,最大价值的区间有多少个,以及这些区间分别是什么。

 

【输入格式】

从文件point.in中读入数据
第一行一个整数n。
第二行n个整数ai

 

【输出格式】

输出到文件point.out中
第一行两个整数,num和val,分别表示价值最大的区间的个数以及最大价值。
第二行num个整数,按升序输出每一个最大价值区间的L。

 

【样例输入1】

5
4 6 9 3 6

 

【样例输出1】

1 3
2

 

【样例输入2】

30
15 15 3 30 9 30 27 11 5 15 20 10 25 20 30 15 30 15 25 5 10 20 7 7 16 2 7 7 28 7

 

【样例输出2】

1 13
9

 

【数据规模和约定】

对于30%的数据,1≤n≤30, 1≤ai≤32
对于60%的数据,1≤n≤3000, 1≤ai≤1024
对于80%的数据,1≤n≤300000, 1≤ai≤1048576
对于100%的数据,1≤n≤500000, 1≤ai<232

 

【NYG教你学数学】

题意中这一句话:
存在L≤k≤R使得∀i∈[L,R]都有a| ai
的含义是:
在L到R中至少有一个位置k,满足对于L到R中的所有位置i,都有ak整除ai

 

解析:

  读完一遍,发现可以二分答案

  $check$的时候枚举左端点,如果用线段树维护$gcd$的话,时间复杂度就是$O(Nlog^{3}N)$,显然吃不消

  考虑用$st$表维护出$gcd$和$min$,这样查询就是$O(NlogN)$的,总时间复杂度是$O(Nlog^{2})$的,就可过了

  一开始的时候我还想多了,以为查询一段区间的$gcd$必须把区间拆分成几个不相交的区间,结果发现和普通的$st$表一样,给首位两段预处理好的$gcd$再取一次$gcd$就行了

 代码:

 

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 500004;

template<class T>
inline void read(T &ret)
{
    T f=1;
    char c;
    while((c=getchar())&&(c<'0'||c>'9'))if(c=='-')f=-1;
    ret=c-'0';
    while((c=getchar())&&(c>='0'&&c<='9'))ret = (ret<<3)+(ret<<1)+c-'0';
    ret *= f;
}

int n, lg[maxn], ans[maxn], val, cnt;
ll a[maxn];
ll gc[25][maxn], mn[25][maxn];

struct pr{
    ll fir, sec;
};

inline ll gcd(ll x, ll y)
{
    return y == 0? x: gcd(y, x % y);
}

inline pr getpr(int x, int len)
{
    pr ret;
    ret.fir = gcd(gc[lg[len]][x], gc[lg[len]][x+len-(1<<lg[len])]);
    ret.sec = min(mn[lg[len]][x], mn[lg[len]][x+len-(1<<lg[len])]);
    return ret;
}

inline bool check(int x)
{
    pr y;
    for(register int i = 1; i <= n - x + 1; ++i)
    {
        y = getpr(i, x);
        if(y.fir == y.sec)
            return 1;
    }
    return 0;
}

void work()
{
    pr y;    
    for(register int i = 1; i <= n - val + 1; ++i)
    {
        y = getpr(i, val);
        if(y.fir == y.sec)
            ans[++cnt] = i;
    }
}

int main()
{
    freopen("point.in", "r", stdin);
    freopen("point.out", "w", stdout);
    read(n);
    lg[0] = -1;
    for(register int i = 1; i <= n; ++i)
    {
        read(a[i]);
        lg[i] = lg[i>>1] + 1;
        gc[0][i] = mn[0][i] = a[i];
    }
    for(register int j = 1; j <= lg[n]; ++j)
        for(register int i = 1; i <= n - (1<<j) + 1; ++i)
        {
            gc[j][i] = gcd(gc[j-1][i], gc[j-1][i+(1<<(j-1))]);
            mn[j][i] = min(mn[j-1][i], mn[j-1][i+(1<<(j-1))]);
        }
    register int l = 1, r = n, mid;
    while(l <= r)
    {
        mid = (l + r)>>1;
        if(check(mid))
            val = mid, l = mid + 1;
        else
            r = mid - 1;
    }
    work();
    printf("%d %d\n", cnt, val - 1);
    for(register int i = 1; i <= cnt; ++i)
        printf("%d ", ans[i]);
    return 0;
}
point

 

 

T3:excellent

NYG的序列拆分


【问题描述】

因为NYG很老实,于是他又对放入背包的序列开始了思考。
由于NYG很擅长序列问题,他的一大爱好就是对这些序列进行拆分。
一个长为n的正整数序列A,对1≤i≤n都有Ai∈[l, r],NYG定义它的一个拆分为一个长为k的序列S,满足:
1. S1 = 1
2. Sk = n +1
3. Si < Si+1,1≤i<k
NYG认为,一个拆分是优秀(高贵)的,当且仅当对于每一个i, 1≤i<k,A中的元素$A_{S _{i}}$, $A_{S _{i}+1}$ . . . , $A_{S _{i+1}-1}$构成等比数列。
给出n, l, r, NYG需要你求出所有可能的(r − l +1)n个序列的优秀拆分的个数总和。由于答案可能很大,输出对109+7取模。
NYG觉得这样的拆分实在是太多了,所以就把任务扔给了你。


【输入格式】

从文件excellent.in中读入数据
第一行一个整数T, 表示数据组数。
接下来扔行每行三个整数n, l, r, 意义如上所述。


【输出格式】

输出到文件excellent.out中
输出共T行,每行一个整数表示答案。


【样例输入1】

4
1 1 2
10 6 6
3 1 4
100 1000 100000


【样例输出1】

2
512
198
540522901


【数据规模和约定】

保证T≤10, 1≤l≤r≤107, 1≤n≤1018
我们用$\sum$

标签:...,cnt,NOIP,int,9.13,bmatrix,Test,NYG,dp
来源: https://www.cnblogs.com/Joker-Yza/p/11518001.html