NOIP模拟题——计数

【题目描述】
我们都爱奎奎,最近奎奎给大家出了一道题。
他告诉了我们一个n*m 的矩阵点,在这个矩阵中的点可以连接成很多线,求
长度等于某一长度的线的条数。
【输入】)
第一行三个正整数n,m,t,第2-t+1 行为所求Wi。
【输出】
输出1 行,共t 个数,第i 个数为满足长度Wi 的条数。
【输入样例1】
3 3 1 
1

例如此为3*3 的矩阵点

【输出样例1】
12
【输入样例2】
7 11 1
5
【输出样例2】
168
【输入样例3】
3 5 1
2
【输出样例3】
14
【数据说明】
测试点数据范围
1 2 N<=2000;M<=2000;T<=100
3 4 N<=1000000;M<=1000000;T<=100
5 6 N<=10000000;M<=10000000;T<=100
7 8 N<=100000000;M<=100000000;T<=100
9 10 N<=1000000000;M<=1000000000;T<=100
W<=2max(n,m);

这道题就是找勾股数,但是太难想了。

先考虑直线水平和竖直的情况:

if(n>x)
ans+=(n-x)*m;
if(m>x)
ans+=(m-x)*n;

在考虑斜着的情况:

我们设要找的长度为r,则设x²+y²=r²

得到x=sqrt((r+y)*(r-y))

设d=gcd(r+y,r-y),A=(r-y)/d,B=(r+y)/d

得到x=d*sqrt(A*B),推出A*B是完全平方数,又因为A,B是两数除以最大公因数

得出:A、B是互质的完全平方数

A+B=2*r/d得出(A+B)*d=2*r

枚举d从1~sqrt(2*r)、2*r%d=0(原因:若d大于根号2r后,相当于A+B的值和d的值颠倒,重复算了)

再枚举a从1~sqrt(r/d)——保证A<B,再判断B是否是完全平方数

若满足,联立A=(r-y)/d,B=(r+y)/d得:

y=(A-B)*d/2,通过r和y得出x

再算时间复杂度。枚举d用根号2*r,约5*1e4

再枚举1~根号r/d,应该大于100,再乘上100组数据,超时。

但为什么不超时?

因为d的取值不可能是到根号2*r,所以后面的循环次数也大幅降低了。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cmath>
 5 using namespace std;
 6 int n,m,t;
 7 int gcd(int x,int y)
 8 {
 9     if(y==0)return x;
10     return gcd(y,x%y);
11 }
12 int main()
13 {
14     freopen("amount.in","r",stdin);
15     freopen("amount.out","w",stdout);
16     scanf("%d%d%d",&n,&m,&t);
17     if(n>m)swap(n,m);//n小
18     for(int j=1;j<=t;j++)
19     {
20         long long x;scanf("%I64d",&x);
21         long long ans=0;
22         if(n>x)
23         ans+=(n-x)*m;
24         if(m>x)
25         ans+=(m-x)*n;
26         for(long long d=1;d*d<=2*x;d++)//枚举d
27             if(2*x%d==0)
28             {
29                 for(long long a=1;a*a<x/d;a++)
30                 {
31
32                     long long A=a*a;
33                     long long B=2*x/d-A;
34                     long long C=int(sqrt(B+0.5));
35                     if(C*C!=B)continue;//得出A、B
36                     if(gcd(a,C)!=1)continue;
37                     long long k1=(B-A)*d/2;
38                     long long k2=sqrt(x*x-k1*k1+0.5);
39                     if(k1*k1+k2*k2!=x*x)continue;
40                     if(k1>k2)continue;
41                     if(k1<=n&&k2<=m)
42                     ans+=(n-k1)*(m-k2)*2;
43                     if(k1<=m&&k2<=n)
44                     ans+=(n-k2)*(m-k1)*2;
45                 }
46                 long long k=2*x/d;
47                 if(2*x%k==0)
48                 for(long long a=1;a*a<x/k;a++)
49                 {
50                     long long A=a*a;
51                     long long B=2*x/k-A;
52                     long long C=sqrt(B+0.5);
53                     if(gcd(a,C)!=1)continue;
54                     if(C*C!=B)continue;//得出A、B
55                     long long k1=(B-A)*k/2;
56                     long long k2=sqrt(x*x-k1*k1+0.5);
57                     if(k1*k1+k2*k2!=x*x)continue;
58                     if(k1>k2)continue;
59                     if(k1<=n&&k2<=m)
60                     ans+=(n-k1)*(m-k2)*2;
61                     if(k1<=m&&k2<=n)
62                     ans+=(n-k2)*(m-k1)*2;
63                 }
64             }
65         printf("%I64d ",ans);
66     }
67     return 0;
68 }

我不爱奎奎。

时间: 2024-08-07 04:15:25

NOIP模拟题——计数的相关文章

8.22 NOIP 模拟题

  8.22 NOIP 模拟题 编译命令 g++ -o * *.cpp gcc -o * *.c fpc *.pas 编译器版本 g++/gcc 4.9.2 fpc 2.6.2 评测环境 64 位 Linux, 3.3GHZ CPU 评测软件 Lemon 评测方式 忽略行末空格和回车 特别注意:c/c++ 选手使用 printf 输出 64 位整数请使用%lld 1 注意事项 A 债务 文件名                            输入文件             输出文件  

[BZOJ入门OJ2092][Noip模拟题]舞会

2092: [Noip模拟题]舞会 Time Limit: 20 Sec  Memory Limit: 256 MB Submit: 9  Solved: 5 [Submit][Status][Web Board] Description 学校举行舞会啦,一共有N个人参加,所有人站成一排,从左开始编号,最左边的人编号为1 ,最右边的为N.每个人跳舞的熟练度我们用一个整数表示,第i个人的熟练度为Ai,每次熟 练度最接近的一对相邻男女会出列跳舞,如果有多对那么最左边的那一对会先出列,请你给 出出列跳

noip模拟题题解集

最近做模拟题看到一些好的题及题解. 升格思想: 核电站问题 一个核电站有N个放核物质的坑,坑排列在一条直线上.如果连续M个坑中放入核物质,则会发生爆炸,于是,在某些坑中可能不放核物质. 任务:对于给定的N和M,求不发生爆炸的放置核物质的方案总数 输入:输入文件只一行,两个正整数N,M( 1<N<50,2≤M≤5) 输出:输出文件只有一个正整数S,表示方案总数. 运用升格思想.设N个坑不会发生爆炸的方案数是f[N],那么我们假设N以前的坑的方案 都已知了,那么我们只需要考虑第N个坑如何放即可(顺

9.22 NOIP模拟题

吉林省信息学奥赛 2017 冬令营                                                                                                                                                                                                      day2 嗯 今天题目好水 嗯 今天爆零了好伤心...... 值得纪念

6.19 noip模拟题(题目及解析转自 hzwer 2014-3-15 NOIP模拟赛)

Problem 1 高级打字机(type.cpp/c/pas) [题目描述] 早苗入手了最新的高级打字机.最新款自然有着与以往不同的功能,那就是它具备撤销功能,厉害吧. 请为这种高级打字机设计一个程序,支持如下3种操作: 1.T x:在文章末尾打下一个小写字母x.(type操作) 2.U x:撤销最后的x次修改操作.(Undo操作) (注意Query操作并不算修改操作) 3.Q x:询问当前文章中第x个字母并输出.(Query操作) 文章一开始可以视为空串. [输入格式] 第1行:一个整数n,表

NOIP模拟题 2017.7.3 - 模拟 - 贪心 - 记忆化搜索

直接暴力模拟,注意判数据结构为空时的取出操作. Code 1 #include<iostream> 2 #include<cstdio> 3 #include<ctime> 4 #include<cctype> 5 #include<cstring> 6 #include<cstdlib> 7 #include<fstream> 8 #include<sstream> 9 #include<algorit

【noip模拟题】天神下凡(贪心)

vijos某次模拟赛原题... 处理出每个圆的一级祖先就行了... 其实没有那么麻烦,贪心即可出解. 我们将每个圆转换成线段后按左端点小右端点大的方法排序 然后维护一个栈: 对于每一个圆i 如果栈顶右端点比圆i的右端点小,则出栈,直到栈空 否则i的一级祖先就是栈顶,并且加入i到栈. 证明: 因为左端点排序,所以问题转换为找一个最小的右端点能够包含此线段 假如栈顶的右端点比当前右端点小,显然对于所有将来的线段,不可能包含将来的线段(或者说,尽管能,也不是最优解,因为最优解就是当前i) 然后如果有n

【noip模拟题】挖掘机(模拟题+精度)

这题直接模拟. 可是我挂在了最后两个点上QAQ.唯一注意的是注意精度啊...用来double后边转成整数就忘记用longlong...sad #include <cstdio> #include <cstring> #include <cmath> #include <string> #include <iostream> #include <algorithm> #include <queue> #include <

【noip模拟题】迎接仪式(dp+特殊的技巧)

好神的一题... 这是一道DP题,本题的难点在于状态的确定,由于调整是任意的,很难划分状态,我们略微修改一下调整的形式:把一次’j’和’z’交换看做两次变换:’j’->’z’;’z’->’j’ (zz交换和jj交换是没有意义的,不作考虑);于是最多’j’->'z' 'z'->'j'各K次. F[i,j,k]:=F[i-2,j-x,k-y]+1;If A[i-1]=j then x=0 else x=1If A[i]=z then y=0 else y=1 然后最后要看是否有那么多个