noip模拟题11.17 距noip2016还剩一天

T1 素数密度

这里写图片描述

很容易想到一个性质:一个数 n 如果没有小于√n 的因子,那么这个数肯定是素数。那么我们可以先打一个1-√R 的素数表,枚举素数,小于 L 的数中最大的枚举的素数的倍数,然后依次往后筛掉这个素数的倍数。
代码:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
long long tot,judge[50005],vis[2000005];
long long prime[50005];
int main()
{
    freopen("prime.in","r",stdin);
    freopen("prime.out","w",stdout);
    long long l,r,ans=0;scanf(AUTO,&l);scanf(AUTO,&r);
    for(long long i=2;i*i<=r;i++)
    {
        if(!judge[i])
            prime[++tot]=i;
        for(int j=1;j<=tot;j++)
        {
            if(i*prime[j]>sqrt(r))break;
            judge[i*prime[j]]=1;
            if(i%prime[j]==0)break;
        }
    }//线性筛素数
    for(long long k=1;k<=tot;k++)
    {
        long long tmp=l/prime[k];
        long long i=tmp*prime[k];
        for(long long j=i;j<=r;j+=prime[k])
            if(j<46350&&j==prime[k])continue;
            else if(j>=l)
                vis[j-l]=1;
    }
    for(long long i=l;i<=r;i++)
        if(!vis[i-l])
            ans++;
    printf(AUTO,ans);
    return 0;
}

T2 数页码

这里写图片描述

我居然在考场上写对了一道dp题!!!!!!
祝贺!!!!!!!
dp[i][j] 表示目前的数有 j+1 位,最大位的数字为 i 的所有方案数,那么很明显,举个例子,dp[3][3] 就表示从第 1 页一直到第 3999 页的方案数。
考虑到,比如我们要查 3456 页,那么很明显 dp[3][3] 就算多了,于是我们可以先算第 1 页到第 3000 页,也就是 dp[2][3]+1,然后加上后 456 页中的 3(因为页码是3456,算后面三位数的时候要加上之前没算的千位3),也就是加上 3*456,然后再算 456,也就是 dp[3][2]+1……以此类推,注意只有一位的特殊情况。
代码:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
long long dp[15][15],op[15];
int main()
{
    freopen("count.in","r",stdin);
    freopen("count.out","w",stdout);
    int n;scanf("%d",&n);
    for(int i=0;i<=9;i++)
        dp[i][0]=i+dp[i-1][0];
    int qp=10;
    for(int i=1;i<=12;i++)
    {
        op[i]=qp;
        qp*=10;
    }
    int t=n,wei=0,ac=1;
    while(t)
    {
        ac*=10;
        wei++;
        t/=10;
    }
    ac/=10;
    if(wei==1){printf("%d",dp[n][0]);return 0;}
    for(int i=1;i<=wei;i++)
        for(int j=1;j<=9;j++)
        {
            if(j==1)
                dp[j][i]=dp[9][i-1]*2+j*op[i]+dp[j-1][i];
            else dp[j][i]=dp[9][i-1]+j*op[i]+dp[j-1][i];
        }
    long long ans=0,qte=1,tot=0;
    while(ac)
    {
        int tmp=(n/ac)-1;
        if(tmp>0&&ac>1)
        {
            ans+=dp[tmp][wei-1]+tmp+1;
            ans+=(tmp+1)*(n-(tmp+1)*ac);
        }
        else if(tmp==0&&ac>1)
        {
            ans+=dp[9][wei-2]+tmp+1;
            ans+=(tmp+1)*(n-(tmp+1)*ac);
        }
        else if(ac==1)
            ans+=dp[tmp+1][wei-1];
        n=n-(tmp+1)*ac;ac/=10;wei--;
    }
    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

10000×10000的数组开不下。
用vector保存每一列上的点、每一行上的点。每次查询一个矩阵的时候,这个矩阵被保护,当且仅当每一行都有车或者每一列都有车。那么我们可以对于矩阵的每一行用二分查询是否有在矩阵内的车,如果查询到一行没有,(小优化)直接跳到查询每一列是否有在矩阵内的车。如果到最后一行(列)一直都有,说明这个矩阵被保护,否则不被。
能过60%的数据,正解用什么扫描线+线段树…我是废人。= =

#include<set>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
vector<int>lie[100005];
vector<int>hang[100005];
int visx[100005],visy[100005],tot1,tot2,qu1[100005],qu2[100005];
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
inline bool findx(int k,int last,int top)
{
    if(lie[k].size()==0)return false;
    if(lie[k].size()==1)
    {
        if(lie[k][0]<=top&&lie[k][0]>=last)return true;
        else return false;
    }
    int l=0,r=lie[k].size()-1;
    do
    {
        int mid=(l+r)>>1;
        if(lie[k][mid]<=top&&lie[k][mid]>=last)return true;
        else if(lie[k][mid]>top)
            r=mid;
        else if(lie[k][mid]<last)
            l=mid+1;
    }while(l<r);
    for(int i=l-1;i<=l+1;i++)
        if(lie[k][i]<=top&&lie[k][i]>=last)return true;
    return false;
}
inline bool findy(int k,int last,int top)
{
    if(hang[k].size()==0)return false;
    if(hang[k].size()==1)
    {
        if(hang[k][0]<=top&&hang[k][0]>=last)return true;
        else return false;
    }
    int l=0,r=hang[k].size()-1;
    do
    {
        int mid=(l+r)>>1;
        if(hang[k][mid]<=top&&hang[k][mid]>=last)return true;
        else if(hang[k][mid]>top)
            r=mid;
        else if(hang[k][mid]<last)
            l=mid+1;
    }while(l<r);
    for(int i=l-1;i<=l+1;i++)
        if(hang[k][i]<=top&&hang[k][i]>=last)return true;
    return false;
}
inline bool judge(int x1,int y1,int x2,int y2)
{
    for(int i=x1;i<=x2;++i)
    {
        if(!findx(i,y1,y2))
            break;
        if(i==x2)
            return true;
    }
    for(int i=y1;i<=y2;++i)
        if(!findy(i,x1,x2))
            return false;
    return true;
}
int main()
{
    freopen("brother.in","r",stdin);
    freopen("brother.out","w",stdout);
    int n=read(),m=read(),k=read(),q=read();
    for(int i=1;i<=k;++i)
    {
        int x=read(),y=read();
        lie[x].push_back(y);
        if(!qu1[x])
        {
            visx[++tot1]=x;
            qu1[x]=1;
        }
        hang[y].push_back(x);
        if(!qu2[y])
        {
            visy[++tot2]=y;
            qu2[y]=1;
        }
    }
    sort(visx+1,tot1+1+visx);
    sort(visy+1,tot2+1+visy);
    for(int i=1;i<=tot1;++i)
        sort(lie[visx[i]].begin(),lie[visx[i]].end());
    for(int i=1;i<=tot2;++i)
        sort(hang[visy[i]].begin(),hang[visy[i]].end());
    for(int i=1;i<=q;i++)
    {
        int x1=read(),y1=read(),x2=read(),y2=read();
        if(judge(x1,y1,x2,y2))printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值