您的位置:首页 > 其它

noip模拟题11.17 距noip2016还剩一天

2016-11-17 15:12 260 查看

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
[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个矩形,表示矩形内部是战略要地。
d47c

秋实大哥要求一个矩形内的每一个格子,都至少能被一辆在矩形内的车攻击到,那么这个矩形就是被完整保护的。

现在秋实大哥想知道每一个矩形是否被完整保护。

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  模拟题