[NOIP模拟题][数学][乱搞][DP?][扫描线][线段树]

来源:互联网 发布:eclipse使用ubuntu字体 编辑:程序博客网 时间:2024/04/30 05:54

T1

给定区间[ L,R ]{L<=R<=21亿},区间长度<=1e6,求区间内素数个数

看数据范围就知道应该从这个区间入手
想到一个重要的性质,n以内的数最多只有一个大于根号n的质因子,那么我们如果只用根号n以内的素数,一定可以将n以内的素数筛出来
那么就可以先将根号n以内的素数筛出来,再用它们来筛一遍[L,R]即可

#include<cstdio>#include<cstring>#include<cctype>#include<algorithm>#include<cmath>using namespace std;typedef long long LL;const int maxlen=1e6+5;int n,m,prime[maxlen],cnt,len,ans;bool vis[maxlen],mark[maxlen];int readint(){    int x=0; char ch=getchar();    while (!isdigit(ch)) ch=getchar();    while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0'; ch=getchar();}    return x;}void init(){    int lim=(int)sqrt(n+0.5);    for (int i=2;i<=lim;i++)    {        if (!vis[i]) prime[++cnt]=i;        for (int j=1;j<=cnt;j++)        {            int temp=i*prime[j];            if (temp>lim) break;            vis[temp]=true;            if (i%prime[j]) break;        }    }}int main(){    freopen("prime.in","r",stdin);    freopen("prime.out","w",stdout);    m=readint(); n=readint(); len=n-m+1;     init();    for (int i=1;i<=cnt;i++)    {        int k=m/prime[i]; k=k*prime[i];        if (k<=prime[i]) k=prime[i]<<1;        if (k<m) k+=prime[i];        for (LL j=k;j<=n;j+=prime[i]) mark[j-m+1]=true;    }    for (int i=1;i<=len;i++) if (!mark[i]) ans++;    printf("%d",ans);    return 0;}

T2

对于一个数n,它的贡献为每位上的数值,例如w(123)=1+2+3
求1-n的贡献之和,n<=1e9

没10个数,个位贡献之和为45,每一百个数,十位贡献之和为450,大概就这样随便算就行了
考试时思维很混乱,代码写的丑

#include<cstdio>#include<cstring>#include<cctype>#include<algorithm>#ifdef WIN32#define AUTO "%I64d"#else #define AUTO "%lld"#endif using namespace std;typedef long long LL;const LL val=1+2+3+4+5+6+7+8+9;LL n,flag,ans,last;int readint(){    int x=0; char ch=getchar();    while (!isdigit(ch)) ch=getchar();    while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0'; ch=getchar();}    return x;}int main(){//  freopen("count.in","r",stdin);//  freopen("count.out","w",stdout);    n=readint();    ans+=n/10*val;    for (int i=1;i<=n%10;i++) ans+=i;    last=n%10; flag=10;    LL x=n/10;    while (x)    {        ans+=x/10*flag*val;        LL temp=x%10;        for (int i=1;i<temp;i++) ans+=i*flag;        ans+=temp*(last+1);        last=n%(flag*10);        flag*=10;        x/=10;    }    printf(AUTO,ans);    return 0;}

T3

Description
胜负胸中料已明,又从堂上出奇兵。秋实大哥是一个下棋好手,独孤求败的他觉得下棋已经无法满足他了,他开始研究一种新的玩法。
在一个n×m的棋盘上,放置了k个车,并且他在棋盘上标出了q个矩形,表示矩形内部是战略要地。
秋实大哥要求一个矩形内的每一个格子,都至少能被一辆在矩形内的车攻击到,那么这个矩形就是被完整保护的。
现在秋实大哥想知道每一个矩形是否被完整保护。
Input
第一行包含四个整数n,m,k,q,表示棋盘的大小,车的数量以及矩形的数量。
接来下k行,每行包含两个整数x,y,表示有一辆车位于从左往右第x列,从下往上第y行。
接下来q行,每行包含四个整数x1,y1,x2,y2,表示一个矩形的左下角和右上角坐标。
1≤n,m≤1e5,1≤k,q≤2e5,1≤x1≤x2≤1e5,1≤y1≤y2≤1e5,1≤x≤1e5,1≤y≤1e5。
Output
输出q行,对于每一次询问,这个矩形若被完整保护了输出”YES”,否则输出”NO”。
Sample input
4 3 3 3
1 1
3 2
2 3
2 3 2 3
2 1 3 3
1 2 2 3
Sample Output
YES
YES
NO
Limit
此题无小数据

无小数据是假的,而且裸暴力都有60分
不过暴力还是需要理解题意
那就是想要满足一个矩形被覆盖,必选满足所有横线上有点或所有竖线上有点
那么就可以随便暴力了
我用的是前缀和

下面是正解
首先我们来处理每条横线上有点的情况
以所有纵坐标为结点建一棵线段树,每个结点维护更新当前的横坐标,一段区间即维护横坐标的最小值
那我们以横坐标从左往右扫描,遇到车(x,y)就更新y的x,遇到矩形(x1,y1,x2,y2)的右边界x2就查询区间(y1,y2)横坐标最小值,若最小值大于等于x1,那么矩形是可以被完全覆盖的
不过因为要处理两种情况,代码可能会写的十分冗杂,可以考虑第一次处理横线,然后将车和矩形的横纵坐标翻转,再相同的处理竖线即可

#include<cstdio>#include<cstring>#include<algorithm>#include<cctype>#include<vector>using namespace std;const int N=1e5;int n,m,k,q;bool ans[N<<1|1];int readint(){    int x=0; char ch=getchar();    while (!isdigit(ch)) ch=getchar();    while (isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();}    return x;}struct Square{    int x1,y1,x2,y2,ID;    bool operator<(const Square &temp)const     {        return x2<temp.x2;    }    void read(int id)    {        x1=readint(); y1=readint(); x2=readint(); y2=readint();        ID=id;     }}square[N<<1|1];struct Car{    int x,y;    bool operator<(const Car &temp)const     {        return x<temp.x;    }    void read()    {        x=readint(); y=readint();    }}car[N<<1|1];struct Seg{    int L,R,val;}seg[N<<2];#define Lson (tr<<1)#define Rson (tr<<1|1)void build(int L,int R,int tr){    seg[tr].L=L; seg[tr].R=R; seg[tr].val=0;    if (L==R) return ;    int mid=(L+R)>>1;    build(L,mid,Lson); build(mid+1,R,Rson);}void pushup(int tr){    seg[tr].val=min(seg[Lson].val,seg[Rson].val);}void update(int tr,int pos,int add){    if (seg[tr].L==seg[tr].R)    {        seg[tr].val=add;        return ;    }    int mid=(seg[tr].L+seg[tr].R)>>1;    if (pos<=mid) update(Lson,pos,add);    else update(Rson,pos,add);    pushup(tr);}int query(int tr,int s,int t){    if (seg[tr].L==s&&seg[tr].R==t) return seg[tr].val;    int mid=(seg[tr].L+seg[tr].R)>>1;    if (t<=mid) return query(Lson,s,t);    if (s>=mid+1) return query(Rson,s,t);    return min(query(Lson,s,mid),query(Rson,mid+1,t));}void work(int X,int Y){    build(1,Y,1);    sort(car+1,car+k+1); sort(square+1,square+q+1);    int posc=1,poss=1;    for (int i=1;i<=X;i++)    {        while (posc<=k&&car[posc].x<=i) update(1,car[posc].y,car[posc].x),posc++;        while (poss<=q&&square[poss].x2==i)        {            int temp=query(1,square[poss].y1,square[poss].y2);            if (temp>=square[poss].x1) ans[square[poss].ID]=true;             poss++;        }    }}void reserve(){    for (int i=1;i<=k;i++) swap(car[i].x,car[i].y);    for (int i=1;i<=q;i++) swap(square[i].x1,square[i].y1),swap(square[i].x2,square[i].y2);}int main(){    freopen("brother.in","r",stdin);    freopen("brother.out","w",stdout);    n=readint(); m=readint(); k=readint(); q=readint();    for (int i=1;i<=k;i++) car[i].read();    for (int i=1;i<=q;i++) square[i].read(i);    work(n,m); reserve(); work(m,n);    for (int i=1;i<=q;i++)      if (!ans[i]) puts("NO");      else puts("YES");    return 0;}
0 0