68测试20161117数论乱搞前缀和

Posted qzgxlx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了68测试20161117数论乱搞前缀和相关的知识,希望对你有一定的参考价值。

第一题:

  素数密度:给一个区间[L,R],求区间中的素数的个数。L、R<=214748367,L-R<=1000000

解:看到这么大的数据都有点慎得慌。首先,根据筛数法,这么大的数只需要筛sqrt(r)大的素数就可以了。把1~sqrt(r)的素数筛出来,然后用这些素数筛L~R的数。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define ll long long 
 6 #define maxn 1000005
 7 #define N 20005
 8 using namespace std;
 9 int l,r,len,ans,pri[maxn],idx;
10 bool vis[maxn],v[maxn];
11 long long ti;
12 void workk()
13 {
14     for (int i=2;i<=maxn;i++)//注意是maxn,不写i*i<=r是因为最后一次乘的时候可能会超int 
15     if (!vis[i]){
16         pri[++idx]=i;
17         for (ll j=(ll)i*(ll)i;j<=maxn;j+=i)
18         if (!vis[j]){
19             vis[j]=true;
20         }
21     }
22 }
23 int main()
24 {
25     freopen("prime.in","r",stdin);
26     freopen("prime.out","w",stdout);
27     scanf("%d%d",&l,&r);
28     workk();
29     for (int i=1;i<=idx;i++)
30     {
31         int x=r/pri[i]*pri[i];//***找到离R最近的那个要筛掉的数 
32         while (x>pri[i]&&x>=l)//> not >= 因为pri[i]为质数 
33         {
34             v[x-l]=true;x-=pri[i];
35         }
36     }
37     for (int i=0;i<=r-l;i++)
38      if (!v[i]) ans++;
39     printf("%d",ans);
40     return 0;
41 }

第二题:

  从1~n的所有数的各个位的数字之和。即123=1+2+3=6.然后每个1~n的数的和。

解:一看就要找规律。按照位数来数这一位重复了多少1~9(∑=45)和余下的。再把每个位求的答案加起来。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #ifdef WIN32
 6 #define AUTO "%I64d"
 7 #else 
 8 #define AUTO "%lld"
 9 #endif
10 #define ll long long
11 #define INF 1e9
12 using namespace std;
13 ll n,f[15],ans;
14 void pre()
15 {
16     f[1]=45;
17     for (int i=2;i<=10;i++)
18       f[i]=f[i-1]*10;
19 }
20 int main()
21 {
22     freopen("count.in","r",stdin);
23     freopen("count.out","w",stdout);
24     pre();
25     scanf(AUTO,&n);
26     ll x=1;
27     int st=0;
28     for (int i=0;i<10;i++){
29         x*=10;
30         if (x>n){
31             st=i;
32             break;
33         } 
34     }
35     x/=10;
36     while (st>=0)
37     {
38         ll cur=n/x;//当前位的数字 
39         if (st==0) {
40             cur=n%10;
41             for(int i=1;i<=cur;i++) ans+=i;//单独处理个位    
42         }
43         else{
44             ans+=cur*f[st];//这一位有多少整的1~9:如123中十位上重复了12次1~9 
45             ll aa=cur%10;
46             if (aa>1) {
47                 for (int i=1;i<aa;i++)
48                   ans+=x*i;//除了整的1~9还余了很多个,123十位上还应该有10个1 ,233百位上还有100个1,十位上还有10个1,2 
49             }
50             ll bb=n-cur*x;//123百位上还应该有23个1 ,十位上还应该有3+1个2 
51             ans+=(bb+1)*aa;
52         }
53         x/=10;
54         st--;
55     }
56     printf(AUTO,ans);
57     return 0;
58 }

第三题:

矩形
文件名:brother.pas/c/cpp
时限:1S
空间:256M
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。车:象棋中的ju,只能走直线。

  暴力:每一行,每一列的前缀和。只要一个矩阵的所有列或者所有行都有至少一个车。O(q*(n+m))复杂度。

  注意:n为列数,m为行数。。。。。。

60分代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<vector>
 6 #define maxn 3005
 7 #define N 100005
 8 using namespace std;
 9 int n,m,k,q,idx;
10 int l[maxn][maxn],h[maxn][maxn];
11 bool mp[maxn][maxn];
12 int main()
13 {
14     freopen("brother.in","r",stdin);
15     freopen("brother.out","w",stdout);
16     scanf("%d%d%d%d",&n,&m,&k,&q);    
17     for (int i=1;i<=k;i++)
18     {
19         int x,y;
20         scanf("%d%d",&x,&y);
21         //ju[i].xi=x;ju[i].yi=y;
22         mp[x][y]=true;
23     }
24     for (int i=1;i<=n;i++)//lie
25       for (int j=1;j<=m;j++)//hang
26         {
27             l[i][j]=l[i][j-1];
28             h[i][j]=h[i-1][j];
29             if (mp[i][j]) {
30                 l[i][j]++;h[i][j]++;
31             }
32         }
33     for (int i=1;i<=q;i++)
34     {
35         int xi,yi,xj,yj;
36         scanf("%d%d%d%d",&xi,&yi,&xj,&yj);
37         int ti=min(xi,xj),tj=max(xi,xj),tt=min(yi,yj),tv=max(yi,yj);
38         bool hang=true,lie=true;
39         for (int j=ti;j<=tj;j++)
40           if (l[j][tv]-l[j][tt-1]==0) lie=false;
41         for (int j=tt;j<=tv;j++)
42           if (h[tj][j]-h[ti-1][j]==0) hang=false;
43         if (lie||hang){
44             printf("YES\n");
45             continue;
46         } 
47         printf("NO\n");
48     }
49     return 0;
50 }

 

以上是关于68测试20161117数论乱搞前缀和的主要内容,如果未能解决你的问题,请参考以下文章

前缀和乱搞 uoj 267 魔法小程序

SPOJ - POLYNOM Polynomial(数论乱搞)题解

PAT 数列的片段和简单数论

2/13 qaq~~贪心+二位前缀和+数论(求多个数的最大公因数)

bzoj1800: [Ahoi2009]fly 飞行棋(乱搞)

PHP课程总结20161117