11.1 NOIP模拟赛 (afternoon)

来源:互联网 发布:wps for ubuntu 16.04 编辑:程序博客网 时间:2024/06/06 06:33

幸运数字(number)

Time Limit:1000ms Memory Limit:64MB

题目描述

LYK 最近运气很差,例如在 NOIP 初赛中仅仅考了 90 分,刚刚卡进复赛,于是它决定使用一些方法来增加自己的运气值。它觉得,通过收集幸运数字可以快速的增加它的 RP 值。它给幸运数字下了一个定义: 如果一个数x能被3整除或被5整除或被7整除,则这个数为幸运数字。于是它想让你帮帮它在 L~R 中存在多少幸运数字。

输入格式(number.in)

第一行两个数 L,R。

输出格式(number.out)

一个数表示答案。

输入样例

10 15

输出样例

4

数据范围

对于 50%的数据 1<=L<=R<=10^5。对于 60%的数据 1<=L<=R<=10^9。对于 80%的数据 1<=L<=R<=10^18。对于 90%的数据 1<=L<=R<=10^100。对于另外 10%的数据 L=1,1<=R<=10^100。对于 100%的数据 L,R 没有前导 0。

思路;

容易发现1-n中,假设第i个数 i%3==0||i%5==0||i%7==0那么统计出能被3整除的数为ans1能被5整除的数为ans2能被7整除的数为ans3那么我们发现有些数可以同时被3和5整除,例如15同理也有同时被5和7整除,例如 35;也会有同时被3和7整除的数 例如21;还有同时被3、5和7整除的数 例如105可以看出来 只用ans=(ans1+ans2+ans3)是不对的这样多重复了很多数,再减去能同时被两个数整除的数的个数也是不对的因为多减了能同时被3、5、7同时整除的数 所以要再加上能被3个数整除的个数写个简单程序验证一下就明白了最恶心的来了,这题要写高精!!!!!!!高精除、高精加、高精减!!!!!!!

代码:

// 由于我的U盘忘家里了,所以找了另一个大神的%%%%// 等那会U盘再改吧 #include<cstdio>#include<algorithm>#include<cstdlib>#include<iostream>#define N 1000010using namespace std;int n,m;struct node{    int x,y;};node a[N];int read(){    int num=0,flag=1;char c=getchar();    while(c<'0'||c>'9'){if(c=='-')flag=-1;c=getchar();}    while(c>='0'&&c<='9'){num=num*10+c-'0';c=getchar();}    return num*flag;}bool check(int k){    int mn=1e9,mx=-1e9;    for(int i=1;i<=m;i++)    {        if(a[i].y-a[i].x<=k)continue;        mx=max(a[i].x+a[i].y-k,mx);        mn=min(a[i].x+a[i].y+k,mn);    }    if(mx>mn)return false;    mx=-1e9,mn=1e9;    for(int i=1;i<=m;i++)    {        if(a[i].y-a[i].x<=k)continue;        mx=max(a[i].x-a[i].y-k,mx);        mn=min(a[i].x-a[i].y+k,mn);    }    if(mx>mn)return false;    return true;}int main(){    freopen("jh.in","r",stdin);    //freopen("ant.in","r",stdin);    //freopen("ant.out","w",stdout);    int t;scanf("%d%d",&n,&t);    while(t--)    {        int x,y;scanf("%d%d",&x,&y);        if(x>y)swap(x,y);        if(x!=y){a[++m].x=x;a[m].y=y;}    }    int l=0,r=N,ans;    while(l<=r)    {        int mid=(l+r)/2;        if(check(mid))        {            ans=mid;r=mid-1;        }        else l=mid+1;    }    printf("%d",ans);    return 0;}

位运算(bit)

Time Limit:2000ms Memory Limit:64MB

题目描述

lyk 最近在研究位运算。它发现除了 xor,or,and 外还有很多运算。它新定义了一种运算符“#”。具体地,可以由 4 个参数来表示。令 a[i][j]表示 i#j。其中 i,j 与 a 的值均∈[0,1]。当然问题可以扩展为>1 的情况,具体地,可以将两个数分解为 p 位,然后对于每一位执行上述的位运算,再将这个二进制串转化为十进制就可以了。例如当 a[0][0]=0,a[1][1]=0,a[0][1]=1,a[1][0]=1 时,3#4 在 p=3 时等于 7,2#3 在p=4 时等于 1(实际上就是异或运算)。现在 lyk 想知道的是,已知一个长为n的数列 b。它任意选取一个序列 c,满足 c1<c2<...<ck,其中 1≤c1 且 ck≤n,定义这个序列的价值为b{c1}#b{c2}#...#b{ck}的平方。这里我们假设 k 是正整数,因此满足条件的 c 的序列个数一定是 2^n−1 。lyk 想知道所有满足条件的序列的价值总和是多少。由于答案可能很大,你只需输出答案对 1,000,000,007 取模后的结果即可。

输入格式(bit.in)

第一行两个数 n,p。第二行 4 个数表示 a[0][0],a[0][1],a[1][0],a[1][1]。第三行 n 个数表示 bi(0<=bi<2^p)。

输出格式(bit.out)

一个数表示答案。

输入样例

3 300 1 1 01 2 3

输出样例

28

样例解释

{1}的价值为 1,{2}的价值为4,{3}的价值为 9,{1,2}的价值为 9, {1,3}的价值为 4,{2,3}的价值为1,{1,2,3}的价值为0,因此7个子集的价值总和为 28。

数据范围

总共 10 组数据。对于第 1,2 组数据 n<=5。对于第 3,4 组数据 n<=10000,p=1。对于第 5 组数据 a 值均为 0。对于第 6 组数据 a 值均为 1。对于第 7 组数据 a[0][0]=0,a[1][0]=0,a[1][1]=1,a[0][1]=1。对于第 8,9 组数据 n<=1000,p<=10。对于所有数据 n<=10000,1<=p<=30。

思路:

将一个数的平方拆成若干幂次的平方,例如7^2=(1+2+4)^2。观察答案的形式为1*1+1*2+1*4+2*1+2*2+2*4+4*1+4*2+4*4。枚举每两位,令dp[i][j][k]表示到第i位,此时第一位为j,第二位为k的方案总数,累加即可。

代码:

//听的我一脸懵逼 只好放std了#include <cmath>#include <cstdio>#include <cstdlib>#include <iostream>#include <algorithm>#include <assert.h>using namespace std;long long sum,ans;int dp[3][3],DP[3][3];int a[3][3],n,l,k,b[50005],X1,Y1,X2,Y2,i,j;const int MOD=1000000007;int main(){    freopen("bit.in","r",stdin);    freopen("bit.out","w",stdout);    scanf("%d%d",&n,&k); assert(1<=n&&n<=50000&&1<=k&&k<=30);    scanf("%d%d%d%d",&a[0][0],&a[0][1],&a[1][0],&a[1][1]);    assert(0<=a[0][0] && a[0][0]<=1 && 0<=a[0][1] && a[0][1]<=1 && 0<=a[1][0] && a[1][0]<=1 && 0<=a[1][1] && a[1][1]<=1);    for (i=1; i<=n; i++)    {        scanf("%d",&b[i]);        assert(0<=b[i] && b[i]<=(1<<k));    }    for (i=0; i<k; i++)      for (j=i; j<k; j++)      {        for (X1=0; X1<2; X1++)          for (Y1=0; Y1<2; Y1++) dp[X1][Y1]=DP[X1][Y1]=0;        for (l=1; l<=n; l++)        {            for (X1=0; X1<2; X1++)                for (Y1=0; Y1<2; Y1++)                if (dp[X1][Y1])            {                if (b[l]&(1<<i))                   X2=a[X1][1]; else X2=a[X1][0];                if (b[l]&(1<<j))                    Y2=a[Y1][1]; else Y2=a[Y1][0];                DP[X2][Y2]+=dp[X1][Y1];                if (DP[X2][Y2]>=MOD) DP[X2][Y2]-=MOD;            }            if (b[l]&(1<<i)) X2=1; else X2=0;            if (b[l]&(1<<j)) Y2=1; else Y2=0;            DP[X2][Y2]++; if (DP[X2][Y2]>=MOD) DP[X2][Y2]-=MOD;            for (X1=0; X1<2; X1++)              for (Y1=0; Y1<2; Y1++)              {                dp[X1][Y1]+=DP[X1][Y1];                if (dp[X1][Y1]>=MOD) dp[X1][Y1]-=MOD;                DP[X1][Y1]=0;              }        }        sum=(1<<i);        sum*=(1<<j);        sum%=MOD;        if (i!=j) sum+=sum;        ans+=sum*dp[1][1];        ans%=MOD;      }    cout<<ans;    return 0;}

蚂蚁运输(ant)

Time Limit:5000ms Memory Limit:64MB

题目描述

LYK 在观察一些蚂蚁。蚂蚁想要积攒一些货物来过冬。积攒货物的方法是这样的。对于第i只蚂蚁, 它要从li出发, 拿起货物, 走到ri处放下货物, 需要消耗的时间为|ri-li|。而且所有蚂蚁都是可以同时进行的,也就是说,假如有 m 只蚂蚁,那么运输完货物的时间为 max{|ri-li|}。LYK 决定帮蚂蚁一把,它发明了空间传输装置。具体地,当蚂蚁走到 X 处时,它可以不耗费任意时间的情况下瞬间到达 Y,或者从 Y 到达 X。也就是说,一个蚂蚁如果使用了空间传输装置,它耗费的时间将会是 min{|li-X|+|ri-Y|,|li-Y|+|ri-X|},当然蚂蚁也可以选择徒步走到目标点。由于空间传输装置非常昂贵,LYK 打算只建造这么一台机器。并且 LYK 想让蚂蚁运输完货物的时间尽可能短,你能帮帮它吗?

输入格式(ant.in)

第一行两个数 n,m,n 表示 li,ri 的最大值。接下来 m 行,每行两个数 li,ri。

输出格式(ant.out)

一个数表示答案

输入样例

5 21 32 4

输出样例

1

数据范围

对于 20%的数据 n,m<=100。对于 40%的数据 n,m<=1000。对于 60%的数据 n<=100000,m<=1000。对于 80%的数据 n,m<=100000。对于 100%的数据 n,m<=1000000,1<=li,ri<=n(li=ri 时你甚至可以无视这只蚂蚁) 。

样例解释

令空间传输装置的参数中 X=2,Y=3 或者 X=3,Y=2 都行。

思路:

观察到答案具有可二分性。我们可以二分答案。由于路径都是无向的,因此对于任意一条方案li,ri若li>ri则可以交换li和ri。我们设二分的答案为x。对于那些li+x>=ri的方案我们直接默认为可行。我们规定X<=Y。对于li+x<ri的方案。只有一种可能能够完成,即,从li出发,到达X,到达Y,到达ri。也就是说,如果X确定,Y存在于一段区间内。我们来看li>=X的情况。先求出X=n时符合条件的Y的区间。当X慢慢减少时,这个区间肯定也在慢慢合拢,并且满足li>=X的条件也会越来越多。我们可以线性求出所有这个区间。对于li<X的情况也同理。这样就能做到线性判断,总复杂度nlgn。(这里默认n与m同阶)

代码:

#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>#include<cmath>#include<cstdlib>#include<assert.h>using namespace std;int n,m,L[1000005],R[1000005],l,r,mid,i,ll[1000005],rr[1000005];struct node {int x,y;} t[1000005];int cmp(node i,node j) {return i.x<j.x;}bool OK(int x) {    int cnt=m,MIN=2000005,MAX=-5;    for (int i=n; i>=1; i--) {        while (cnt && t[cnt].x==i) {            if (t[cnt].y-t[cnt].x>x) MIN=min(MIN,t[cnt].y-t[cnt].x);            if (t[cnt].y-t[cnt].x>x) MAX=max(MAX,t[cnt].x+t[cnt].y);            cnt--;        }        ll[i]=MAX-x-i; rr[i]=MIN+x+i;    }    cnt=1; MIN=2000005; MAX=-5;    for (int i=1; i<=n; i++) {        while (cnt<=m && t[cnt].x==i) {            if (t[cnt].y-t[cnt].x>x) MIN=min(MIN,t[cnt].x+t[cnt].y);            if (t[cnt].y-t[cnt].x>x) MAX=max(MAX,t[cnt].y-t[cnt].x);            cnt++;        }        ll[i]=max(ll[i],MAX-x+i);        rr[i]=min(rr[i],MIN+x-i);        if (ll[i]<=rr[i]) return true;    }    return false;}int main() {    freopen("ant.in","r",stdin);    freopen("ant.out","w",stdout);    scanf("%d%d",&n,&m);    assert(1<=n && n<=1000000 && 1<=m && m<=1000000);    for (i=1; i<=m; i++) {        scanf("%d%d",&L[i],&R[i]);        assert(1<=L[i] && L[i]<=n && 1<=R[i] && R[i]<=n);        if (L[i]>R[i]) swap(L[i],R[i]);        t[i].x=L[i]; t[i].y=R[i];    }    sort(t+1,t+m+1,cmp);    l=0; r=n; mid=(l+r)/2;    while (l<=r) {        if (OK(mid)) {r=mid-1; mid=(l+r)/2;}         else{            l=mid+1;            mid=(l+r)/2;        }    }    cout<<l;    return 0;}
0 0
原创粉丝点击