没有测试数据,在网上搜到数据的就测了一下。但是。。应该,也许大概没错吧!
第一题:
真分数的个数,f[i] 表示[1,i]之间真分数的个数。 然后直接求出i的真分数个数,递推一下f[i] = f[i - 1] + g(i)
时间复杂度O(n^2)
#include <iostream>
using namespace std;
inline int gcd(int a, int b)
{
while (b != 0)
{
int tmp = b;
b = a % b;
a = tmp;
}
return a;
}
int f[505];
int n;
int main()
{
f[1] = f[0] = 0;
for (int i = 2; i != 500 + 1; ++ i)
{
f[i] = f[i - 1] + 1;
for (int j = 2; j != i; ++ j)
if (gcd(i, j) == 1) ++f[i];
}
cin >> n;
while (n -- )
{
int a, b;
cin >> a>> b;
cout << f[b] - f[a - 1]<<endl;
}
reutrn 0;
}
第二题:
木棒三角形
看起来数据范围,强行O(n^3)穷举都能过?但是我还是O(n^2logn),穷举两层,然后用map判定所需要的第三条边是否存在。
但是n那么小,除非数据量巨大无比,应该没事吧~~~
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
bool f[105];
int a[105];
int n;
int main()
{
while (scanf("%d", &n))
{
memset(f,false, sizeof(f));
for (int i = 0;i != n; ++ i)
{
scanf("%d", a + i);
f[a[i]] = true;
}
double ans = 0;
if (n < 3)
{
printf("My God!\n");
continue;
}
for (int i = 0; i != n; ++ i)
for (int j = 0; j != n; ++ j)//处理精度的瑕疵,可能有缺陷
{
if (i == j) continue;
double A = (double)a[i];
double B = (double)a[j];
double C = sqrt(A * A + B * B);
int tmp = (int)C;
if ((double)tmp != C) continue;
if (!f[tmp]) continue;
if (tmp > a[i] && tmp > a[j])
{
double s = a[i] * a[j] / 2.0;
ans = max(ans , s);
}
}
if (ans == 0) printf("MY God!\n");
else printf("%lf\n", ans);
}
}
第三题:
9个数字,直接暴力穷举所有删除情况,也就是最多2^9级别,才512。
#include <iostream>
#include <cstdio>
using namespace std;
char c[15];
int n, ans, a, de;
void dfs(int p, int k, int tot, int JIE)
{
if (p == -1)
{
if (k) return;
ans = max(ans, tot);
return;
}
dfs(p - 1, k, tot + (c[p] - '0') * JIE, JIE * 10);
dfs(p - 1, k - 1, tot, JIE);
}
int main()
{
scanf("%d", &n);
while (n -- )
{
ans = 0;
scanf("%s %d", &c, &de);
dfs(8, de, 0, 1);
printf("%d\n", ans);
}
return 0;
}
第四题:
赤裸裸的高精度乘法,这没啥好说的(PS:没贴模板,发现我的程序好丑)
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
struct bigint
{
int w;
vector<int>a;
bigint(string t)
{
w = t.size();
for (int i = t.size() -1; i != 0 -1; -- i)
a.push_back(t[i] - '0');
}
bigint(int n)
{
w = n;
for (int i = 0; i != n; ++ i) a.push_back(0);
}
void p()
{
for (int i = w - 1; i != 0 - 1; -- i) cout<<a[i];
cout<<endl;
}
};
char c[500];
bigint operator * (bigint A, bigint B)
{
bool flag = false;
bigint C(A.w + B.w - 1);
for (int i = 0; i != A.w; ++ i)
for (int j = 0; j != B.w; ++ j)
{
C.a[i + j] += A.a[i] * B.a[j];
int tmp = C.a[i + j] / 10;
if (!tmp) continue;
if (i + j == C.w - 1 && !flag)
{
flag = true;
++ C.w;
C.a.push_back(0);
}
C.a[i + j] %= 10;
C.a[i + j + 1] += tmp;
}
C.p();
return C;
}
int main()
{
int nn;
scanf("%d\n", &nn);
while (nn--)
{
gets(c);
bigint A(c);
gets(c);
bigint B(c);
(A * B);
}
return 0;
}
第五题:
经典动态规划数塔,f[i][j] = f[i-1][j -1] + f[i-1][j] 其中考虑一下边界(f[1][j])情况即可
#include <iostream>
#include <cstdio>
using namespace std;
int a[120][120];
int main()
{
int t, n;
scanf("%d", &t);
while (t -- )
{
int ans = 0;
scanf("%d", &n);
for (int i = 0; i != n; ++i)
for (int j = 0; j != i + 1; ++ j ) scanf("%d", &a[i][j]);
for (int i = 1; i != n; ++ i)
{
a[i][0] += a[i - 1][0];
for (int j = 1; j != i + 1; ++ j) a[i][j] += max(a[i - 1][j], a[i - 1][j - 1]);
}
for (int i = 0; i !=n ; ++ i) ans = max(ans, a[n - 1][i]);
printf("%d\n", ans);
}
}
第六题:
字符串判断存在性问题
这真是奇葩题,要考这个一般是考字母树之类的东西吧,但是这读入量,一次才1000. 直接省事用map来判断了...
#include <iostream>
#include <cstring>
#include <cstdio>
#include <map>
using namespace std;
char ch[1000 + 10];
map<string, int>t;
map<string, int>::iterator k;
int main()
{
while (1)
{
t.clear();
gets(ch);
if (ch[0] == '#') break;
string tmp = "";
for (int i = 0; i != strlen(ch); ++ i )
{
if (ch[i]==' ')
{
if (t.find(tmp) == t.end()) t.insert(pair<string, int>(tmp, 1));
tmp = "";
continue;
}
tmp += ch[i];
}
if (t.find(tmp) == t.end()) t.insert(pair<string, int>(tmp, 1));
printf("%d\n", t.size());
}
return 0;
}
第七题:
模拟啊,按照规则模拟一下。 就是题目最后那一行字说明,最后不要输出多余回车。 这个小心一下,不然会WA
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
int n;
int a[25][2];
int main()
{
scanf("%d", &n);
while (1)
{
for (int j = 0; j != 2; ++ j)
for (int i = 0; i != n; ++ i) scanf("%d",&a[i][j]);
int A(0), B(0);
for (int i = 0; i != n; ++ i)
{
#define x a[i][0]
#define y a[i][1]
// int *x = &a[i][0], *y = &a[i][1];
if (x == y) continue;
if (abs(x - y) == 1)
{
if (x == 1 && y == 2) { A += 6; continue; }
if (x == 2 && y == 1) { B += 6; continue; }
if (x < y) A += x + y;
else B += x + y;
continue;
}
if (x > y) A += x;
else B += y;
}
printf("A has %d points. B has %d points.\n", A, B);
scanf("%d", &n);
if (n) printf("\n");
else break;
}
return 0;
}
第八题:
终于有算法题了。。但是也太模板了。
凸包+求凸包面积的题。 数据量非常小,没啥复杂的地方,直接模板贴上过关
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
const int max_n = 10000 + 10;
int n, top;
struct point
{
double x, y;
point(double a, double b):x(a), y(b){}
point():x(0),y(0){}
}pt[max_n], stack[max_n], t0;
double cross(point T, point A, point B)
{
return (A.x - T.x)*(B.y - T.y) - (B.x - T.x)*(A.y - T.y);
}
double dis(point A, point B)
{
return pow(A.x - B.x, 2) + pow(A.y - B.y, 2);
}
void findpoint()
{
int num = 0;
t0 = pt[0];
for (int i = 1; i != n; ++ i)
if (pt[i].x < t0.x || pt[i].x == t0.x && pt[i].y < t0.y) t0 = pt[num = i];
swap(pt[0], pt[num]);
}
bool cmp(point A, point B) //显然希望 排序结果是, A 逆时针 到B
{
double tmp = cross(t0, A, B);
if (tmp > 0) return true;
if (tmp < 0) return false;
return dis(t0, A) > dis(t0, B);//相同的话,让距离远的在前面 ? 不同的人的程序好像这里都有区别?我感觉好像不影响什么
}
void graham()
{
pt[n] = pt[0] ;
stack[0] = pt[0];
stack[1] = pt[1];
stack[2] = pt[2];
top = 2;
for (int i = 3; i != n + 1; ++ i)
{
while (top && cross(stack[top - 1], stack[top], pt[i]) <= 0) -- top;
stack[++top] = pt[i];
}
}
int main()
{
scanf("%d", &n);
for (int i = 0; i != n; ++ i) scanf("%lf%lf", &pt[i].x, &pt[i].y);
findpoint();
sort(pt + 1, pt + n, cmp);
graham();
int ans = 0;
for (int i = 1; i != top; ++ i)
ans += cross(t0 , stack[i - 1], stack[i]);
cout<<ans/100<<endl;
return 0;
}
总结:
没NOIP初中组难- - 陈题+ 水题 + 模板题
带了好的模板, 直接掉凸包和高精度。 剩下的题一点思维量都没有。 希望明年我参赛,能在2小时内ALL KILL