%d 整数的占位符。可以是int short long的占位符。也可以是unsigned int ,unsigned short , unsigned long
%f 浮点数的占位符,包括float double
%s 字符串的占位符,一般字符串存到数组中,所以,字符串和数组经常联系到一起。
%c 字符的占位符,一个字符。char 类型变量相关。
% 和 d ,f ,s ,c之间可以有数字,表示精度或占有字符数。
%10d 这个整数输出的时候,一般情况下,占用10个宽度。如果输出的整数位数小于10,左边加空格,空格和
数字一共10个字符宽度。
%-10d 同上一个。只不过当数字个数不足10个的时候右边补充空格,就是数字后边补充空格。
%10.2f 表示一共10个有效数字,其中最多2个小数。
%-10.2f 同上,但文字后面补充空格。
%10s 字符串占有10个位置。
Tag Archives: C++
Permission denied
c++ 有一个Bug
程序还在运行时会出现Permission denied
仅以为戒
C++保留字
运算符重载
什么是运算符的重载?
运算符与类结合,产生新的含义。
为什么要引入运算符重载?
作用:为了实现类的多态性(多态是指一个函数名有多种含义)
怎么实现运算符的重载?
方式:类的成员函数 或 友元函数(类外的普通函数)
规则:不能重载的运算符有 . 和 .* 和 ?: 和 :: 和 sizeof
友元函数和成员函数的使用场合:一般情况下,建议一元运算符使用成员函数,二元运算符使用友元函数
1、运算符的操作需要修改类对象的状态,则使用成员函数。如需要做左值操作数的运算符(如=,+=,++)
2、运算时,有数和对象的混合运算时,必须使用友元
3、二元运算符中,第一个操作数为非对象时,必须使用友元函数。如输入输出运算符<<和>>
具体规则如下:
运算符 |
建议使用 |
所有一元运算符 |
成员函数 |
= ( ) [ ] -> |
必须是成员函数 |
+= -= /= *= ^= &= != %= >>= <<= , 似乎带等号的都在这里了. |
成员函数 |
所有其它二元运算符, 例如: –,+,*,/ |
友元函数 |
<< >> |
必须是友元函数 |
2. 参数和返回值
当参数不会被改变,一般按const引用来传递(若是使用成员函数重载,函数也为const).
对于返回数值的决定:
1) 如果返回值可能出现在=号左边, 则只能作为左值, 返回非const引用。
2) 如果返回值只能出现在=号右边, 则只需作为右值, 返回const型引用或者const型值。
3) 如果返回值既可能出现在=号左边或者右边, 则其返回值须作为左值, 返回非const引用。
运算符重载举例:
+和 -运算符的重载:
- class Point
- {
- private:
- int x;
- public:
- Point(int x1)
- { x=x1;}
- Point(Point& p)
- { x=p.x;}
- const Point operator+(const Point& p);//使用成员函数重载加号运算符
- friend const Point operator-(const Point& p1,const Point& p2);//使用友元函数重载减号运算符
- };
- const Point Point::operator+(const Point& p)
- {
- return Point(x+p.x);
- }
- Point const operator-(const Point& p1,const Point& p2)
- {
- return Point(p1.x-p2.x);
- }
调用:
- Point a(1);
- Point b(2);
- a+b; //正确,调用成员函数
- a-b; //正确,调用友元函数
- a+1; //正确,先调用类型转换函数,把1变成对象,之后调用成员函数
- a-1; //正确,先调用类型转换函数,把1变成对象,之后调用友元函数
- 1+a; //错误,调用成员函数时,第一个操作数必须是对象,因为第一个操作数还有调用成员函数的功能
- 1-a; //正确,先类型转换 后调用友元函数
总结:
1、由于+ -都是出现在=号的右边,如c=a+b,即会返回一个右值,可以返回const型值
2、后几个表达式讨论的就是,数和对象混合运算符的情况,一般出现这种情况,常使用友元函数
3、双目运算符的重载:
重载运算符函数名:operator@(参数表)
隐式调用形式:obj1+obj2
显式调用形式:obj1.operator+(OBJ obj2)---成员函数
operator+(OBJ obj1,OBJ obj2)---友元函数
执行时,隐式调用形式和显式调用形式都会调用函数operator+()
++和--运算符的重载:
- class Point
- {
- private:
- int x;
- public:
- Point(int x1)
- { x=x1;}
- Point operator++();//成员函数定义自增
- const Point operator++(int x); //后缀可以返回一个const类型的值
- friend Point operator--(Point& p);//友元函数定义--
- friend const Point operator--(Point& p,int x);//后缀可以返回一个const类型的值
- };
- Point Point::operator++()//++obj
- {
- x++;
- return *this;
- }
- const Point Point::operator++(int x)//obj++
- {
- Point temp = *this;
- this->x++;
- return temp;
- }
- Point operator--(Point& p)//--obj
- {
- p.x--;
- return p;
- //前缀形式(--obj)重载的时候没有虚参,通过引用返回*this 或 自身引用,也就是返回变化之后的数值
- }
- const Point operator--(Point& p,int x)//obj--
- {
- Point temp = p;
- p.x--;
- return temp;
- // 后缀形式obj--重载的时候有一个int类型的虚参, 返回原状态的拷贝
- }
函数调用:
- <pre class="cpp" name="code">Point a(1);
- Point b(2);
- a++;//隐式调用成员函数operator++(0),后缀表达式
- ++a;//隐式调用成员函数operator++(),前缀表达式
- b--;//隐式调用友元函数operator--(0),后缀表达式
- --b;//隐式调用友元函数operator--(),前缀表达式
- cout<<a.operator ++(2);//显式调用成员函数operator ++(2),后缀表达式
- cout<<a.operator ++();//显式调用成员函数operator ++(),前缀表达式
- cout<<operator --(b,2);//显式调用友元函数operator --(2),后缀表达式
- cout<<operator --(b);//显式调用友元函数operator --(),前缀表达式 </pre>
总结:
1、a++
函数返回:temp(临时变量)
函数返回是否是const类型:返回是一个拷贝后的临时变量),不能出现在等号的左边(临时变量不能做左值),函数的结果只能做右值,则要返回一个const类型的值
++a
函数返回:*this;
函数返回是否是const类型:返回原状态的本身,返回值可以做左值,即函数的结果可以做左值,则要返回一个非const类型的值
2、前后缀仅从函数名(operator++)无法区分,只能有参数区分,这里引入一个虚参数int x,x可以是任意整数。
3、单目运算符的重载:
重载运算符函数名:operator@(参数表)
隐式调用形式:obj1@ 或 @obj1
显式调用形式:
成员函数:
obj1.operator@( )//前缀
obj1.operator@(0)//后缀
友元函数:
operator@(OBJ obj)//前缀
operator@(OBJ obj,int x)//后缀
执行时,隐式调用形式和显式调用形式都会调用函数operator@()
重载下标运算符[ ]
- class Point
- {
- private:
- int x[5];
- public:
- Point()
- {
- for (int i=0;i<5;i++)
- {
- x[i]=i;
- }
- }
- int& operator[](int y);
- };
- int& Point::operator[](int y)
- {
- static int t=0;
- if (y<5)
- {
- return x[y];
- }
- else
- {
- cout<<"下标出界";
- return t;
- }
- }
调用:
- Point a;
- for (int i=0;i<10;i++)
- {
- cout<<a[i]<<endl;//无论i下标是否越界,每当使用a[i]时,都会调用[]的重载
- }
- a[0]=10;
重载下标运算符[ ]的目的:
1、对象[x] 类似于 数组名[x],更加符合习惯
2、可以对下标越界作出判断
语法:
重载方式:只能使用成员函数重载
函数名:operator[ ](参数表)
参数表:一个参数,且仅有一个参数,该参数设定了下标值,通常为整型,但是也可以为字符串( 看成下标)。
函数调用:显式调用:Obj[arg]-对象[下标]
隐式调用:obj.operator[ ](arg)
返回类型:
1、返回函数引用 + 返回成员的实际类型(由程序员根据函数体定义)
2、因为返回值可以做左值和右值,应该不使用返回值为const类型
但是,为了能访问const对象,下标运算符重载有非const和const两个版本。(待定写)
如:int& Point::operator[](int y)//为什么使用返回引用:返回的值可以做左值,也可以做右值,则必须使用返回引用
重载运算符( )
- class Point
- {
- private:
- int x;
- public:
- Point(int x1)
- { x=x1;}
- const int operator()(const Point& p);
- };
- const int Point::operator()(const Point& p)
- {
- return (x+p.x);
- }
- 调用:
- Point a(1);
- Point b(2);
- cout<<a(b);
重载运算符( )的目的:
1、对象( ) 类似于 函数名(x),更加符合习惯
语法:
重载方式:只能使用成员函数重载
重载后还可以继续重载
函数名:operator( )(参数表)
参数表:参数随意,具体根据实际情况而定。
函数调用:显式调用:Obj(x)
隐式调用:obj.operator( )(x)
返回类型:
1、返回成员的实际类型随意,具体由程序员根据函数体定义
2、因为返回值只能做右值,只读,应该使用返回值为const类型
重载输入输出操作符<< >>
- class Point
- {
- private:
- int x;
- public:
- Point(int x1)
- { x=x1;}
- friend ostream& operator<<(ostream& cout,const Point& p);//使用友元函数重载<<输出运算符
- friend istream& operator>>(istream& cin,Point& p);//使用友元函数重载>>输出运算符
- };
- ostream& operator<<(ostream& cout,const Point& p)
- {
- cout<<p.x<<endl;
- return cout;
- }
- istream& operator>>(istream& cin,Point& p)
- {
- cin>>p.x;
- return cin;
- }
- 调用:
- Point a(1);
- Point b(2);
- cin>>a>>b;
- cout<<a<<b<<endl;
语法:
重载方式:只能使用友元函数重载 且 使用三个引用&
函数名:
输出流: operator<<(参数表)
输入流:operator>>(参数表)
参数表:固定(容易出错啊),两个参数均用引用&
输出流: 必须是两个参数:对输出流ostream& 和 对象
第一个操作数cout,定义在文件iostream中,是标准类类型ostream的对象的引用。
如:ostream& cout,const Point& p
输入流:必须是两个参数:对输入流ostream& 和 对象
第一个操作数是cin,定义在文件iostream,实际上是标准类类型istream的对象的引用
如:instream& cin,const Point& p
函数调用:
输出流: 显式调用:cout<<对象
隐式调用: operator<<(cout,对象)
输入流:显式调用:cin>>对象
隐式调用: operator>>(cin,对象)
返回类型:返回类型固定 + 使用返回函数引用(满足连续输出)
输出流: 返回ostream&
如:ostream& operator<<(ostream& cout,const Point& p)
输入流:返回:istream&
如:istream& operator>>(istream& cin,Point& p)
注意:为什么输入输出操作符的重载必须使用友元函数?
因为:成员函数要求是有对象调用,则第一个参数必须是类的对象,但是<<和>>第一个参数是流的对象引用。
故,不能使用成员函数
求面积 (坐标叉积公式+凹多边形面积-坐标公式)
求面积(AREA)
给出一个简单多边形(没有缺口),它的边要么是垂直的,要么是水平的。要求计算多边形的面积。
多边形被放置在一个X-Y的卡笛尔平面上,它所有的边都平行于两条坐标轴之一。然后按逆时针方向给出各顶点的坐标值。所有的坐标值都是整数(因此多边形的面积也为整数)。
输入
输入文件第一行给出多边形的顶点数n(n≤100)。接下来的几行每行给出多边形一个顶点的坐标值X和Y(都为整数并且用空格隔开)。顶点按逆时针方向逐个给出。并且多边形的每一个顶点的坐标值-200≤x,y≤200。多边形最后是靠从最后一个顶点到第一个顶点画一条边来封闭的。
输出
输出文件仅有一行包含一个整数,表示多边形的面积。
样例
AREA.IN
10
0 0
4 0
4 1
3 1
3 3
2 3
2 2
1 2
1 3
0 3
AREA.OUT
9
叉积公式 A X B= x1y2-x2y1=S(平行四边形)=2S(三角形)=2*|a|*|b|*sinaC
#include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<cmath> #include<functional> #include<algorithm> #include<queue> using namespace std; #define MAXN (100+10) class _vector { public: int x,y; _vector():x(0),y(0){} _vector(int _x,int _y):x(_x),y(_y){} friend int operator*(const _vector a,const _vector b) { return a.x*b.y-a.y*b.x; } }node[MAXN]; istream& operator>>(istream& in,_vector& a) { in>>a.x>>a.y; return in; } int n; int main() { freopen("area.in","r",stdin); freopen("area.out","w",stdout); scanf("%d",&n); for (int i=1;i<=n;i++) cin>>node[i]; node[n+1]=node[1]; int ans=0; for (int i=1;i<=n;i++) ans+=node[i]*node[i+1]; ans=abs(ans); printf("%dn",int(round(double(ans)/2))); // while (1); return 0; }
舞蹈课 (C++堆的优先级与重载)
第三题:舞蹈课(dancingLessons)
时间限制:1秒
内存限制:256MB
输入:dancingLessons.in
输出:dancingLessons.out
问题描述
有n个人参加一个舞蹈课。每个人的舞蹈技术由整数来决定。在舞蹈课的开始,他们从左到右站成一排。当这一排中至少有一对相邻的异性时,舞蹈技术相差最小的那一对会出列并开始跳舞。如果相差最小的不止一对,那么最左边的那一对出列。一对异性出列之后,队伍中的空白按原顺序补上(即:若队伍为ABCD,那么BC出列之后队伍变为AD)。舞蹈技术相差最小即是的绝对值最小。
你的任务是,模拟以上过程,确定跳舞的配对及顺序。
输入
第一行为正整数:队伍中的人数。下一行包含n个字符B或者G,B代表男,G代表女。下一行为n个整数。所有信息按照从左到右的顺序给出。在50%的数据中,。
输出
第一行:出列的总对数k。接下来输出k行,每行是两个整数。按跳舞顺序输出,两个整数代表这一对舞伴的编号(按输入顺序从左往右1至n编号)。请先输出较小的整数,再输出较大的整数。
样例输入
4
BGBG
4 2 4 3
样例输出
2
3 4
1 2
样例输入
4
BGBB
1 1 2 3
样例输出
1
1 2
堆的操作
--堆默认为小根堆(重载Operator<) 小的放前面
注意此处用greater - 大根堆
#include<cstdio> #include<cstring> #include<queue> #include<cmath> #include<cstdlib> #include<iostream> #include<functional> #include<algorithm> using namespace std; #define MAXN (200000 + 10) #define MAXAI (10000000 + 10) int n; char s[MAXN]; int a[MAXN]; bool b[MAXN]; struct pair2 { int x,y,w; }ans[MAXN]; bool operator>(const pair2 a,const pair2 b) { if (a.w==b.w) return a.x>b.x; return a.w>b.w; } void cout_pair(const pair2 a) { printf("%d %dn",a.x,a.y); } priority_queue <pair2, vector<pair2>, greater<pair2> > q; void push(int x,int y) { pair2 now; now.x=x; now.y=y; now.w=abs(a[x]-a[y]); q.push(now); // cout<<"add "<<now.x<<' '<<now.y<<' '<<now.w<<'n'; } int main() { freopen("dancingLessons.in","r",stdin); freopen("dancingLessons.out","w",stdout); scanf("%dn%s",&n,s); for (int i=1;i<=n;i++) scanf("%d",&a[i]); memset(b,0,sizeof(b)); for (int i=1;i<n;i++) if (s[i-1]!=s[i]) push(i,i+1); int tot=0; while (!q.empty()) { pair2 now=q.top(); // cout_pair(now); q.pop(); if (b[now.x]||b[now.y]) continue; b[now.x]=1; b[now.y]=1; ans[++tot]=now; int l=now.x-1,r=now.y+1; if (l<1||r>n) continue; while (l>1&&b[l]) l--; while (r<n&&b[r]) r++; if (b[l]||b[r]) continue; if (s[l-1]!=s[r-1]) push(l,r); } printf("%dn",tot); for (int i=1;i<=tot;i++) cout_pair(ans[i]); // while (1); return 0; }
POJ 3270(Cow Sorting)
这题主要是交换时要求代价最小
先找到环 相同数字 与 同列 相连
1 第一行为起始序列 第二行为目标序列
1 3 4 2 5
1 2
3 4 5
把一个环中最小的那个与指向的数交换
1 3
2 4 5
1 2
3 4 5
最后交换3 2
1 2
3 4 5
1 2
3 4 5
或则调来序列中最小的那个数与环中最小数替换(乘船问题?)
这样就能得到最优解
ans+=min( (sizi-2)*mini+sumi,
(sizi+1)*minn+mini+sumi
#include<cstdio> #include<cmath> #include<iostream> #include<cstdlib> #include<cstring> #include<functional> #include<algorithm> using namespace std; #define MAXN (10000+10) #define MAXAI (100000+10) int n,a[MAXN],a2[MAXN],hpos[MAXAI],ans=0; bool b[MAXN]; int main() { // freopen("cowsorting.in","r",stdin); scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d",&a[i]); memcpy(a2,a,sizeof(a)); sort(a2+1,a2+1+n,less<int>()); int minn=a2[1]; memset(b,false,sizeof(b)); for (int i=1;i<=n;i++) hpos[a[i]]=i; for (int i=1;i<=n;i++) { // cout<<a2[i]<<' '<<a[i]<<endl; if (!b[i]&&a2[i]!=a[i]) { b[i]=1; int mini=a[i],start=i,sizi=1,sumi=a[i]; int now=hpos[a2[i]]; while (now!=start) { b[now]=1; sizi++; sumi+=a[now]; mini=min(mini,a[now]); now=hpos[a2[now]]; } ans+=min((sizi-2)*mini+sumi,(sizi+1)*minn+mini+sumi); } } ///000 // for (int i=1;i<=n;i++) printf("%d ",a2[i]); ///000 printf("%dn",ans); // while (1); return 0; }
NOIP's 算法
NOI、NOIP算法考前总结,带*为NOIP级别的比赛中涉及到的几率不大的算法
一、基础算法
一般都是前几题,会比较简单
1、模拟 注意要写准确,注意细节,简单的模拟一定要AC,复杂的模拟要先用手写清楚再开始遍 例如noip2011
mayan
2、搜索(枚举) 如dfs,bfs,同样简单的尽量AC。有些搜索需要剪枝,尽量刨去不会出现的答案
3、贪心 重点在证明,如果实在没有好的方法又不会证明可以用来骗骗分 例如noip2011
bus
4*、矩阵 关键是构造出正确的矩阵,实现很简单,范围大时要用快速幂
二、动态规划
一般每年必考至少一道
做DP题时,最好先在纸上写好状态转移方程和边界条件
1、背包 分为01背包,部分背包,完全背包等。例如 采药,金明的预算方案等
2、线性DP 这例如 添加号,ioi2003方块消除
3、坐标型DP 例如 noi99棋盘分割
4、区间型DP 例如 noip2005能量项链,noip2008传球游戏
5、树形DP 例如 皇宫看守,noi2012
park,poi-6 tro,poj1947
6、*状压DP 本质就是用一个数字表示一个状态,一般有最小表示法和括号表示法。 例如noi2001炮兵阵地,noi2007生成树计数,SCOI2005互不侵犯的king
7、*斜率优化DP 这类题需要手推公式,然后找到单调性。 例如HNOI2008玩具装箱,APIO2010特别行动队
三、图论
这类题种类非常多
1、最短路 必会的算法,spfa,dijkstra,dijkstra注意用堆优化,尽量用dij+heap而不是spfa。 这类题到处都是
2、最小生成树 稀疏图用kruskal,稠密图用prim,prim也可以堆优化
3、LCA 会一种求LCA的方法就够了,比如Tarjan的离线算法,时间复杂度是O(n+Q)。 例如BZOJ1776
4、强连通分量 Tarjan算法。 例如BZOJ1051
5、欧拉路的问题 例如 sgu101
6、二分图最大匹配 重点是建模。例如BZOJ1059,BZOJ1433,BZOJ1562
7、*最小费用最大流 重点同样是建模。例如noi2012delicacy,sgu185
四、数据结构
NOIP涉及的较少
1、 栈 队列 堆 都是基本算法,必须掌握
2、 并查集 例如 亲戚,noi食物链,BZOJ1015
3、 字典树 快速查找到字符串的方法,一般不单独出现,用来优化其它算法
4、 线段树 很常用的数据结构。例如 BZOJ1798 ,BZOJ1651,BZOJ1230,BZOJ1858
5、 *平衡树 用来维护二叉查找树的。 例如BZOJ1208,BZOJ1503,BZOJ1588
6、 *可并堆(斜堆、左偏树),有时启发式合并也不足以解决问题就要用它了。 例如APIO2012派遣
7、 *伸展树 用来维护序列的增加一个序列,删除一个序列,翻转一个序列等操作。 例如NOI2005序列维护,NOI2003editor
8、 *划分树 求区间第K大 例如poj2104
9、 *AC自动机,多串匹配的经典算法。例如noi2011阿狸的打字机
10、 *二维线段树 类似一维线段树,只不过每个节点存的是一颗线段树,实际就是线段树套线段树。例如noi2012
chess
using STL
|
Number (dp-性质数状态表示)
Number
【题目描述】
明明在做力学作业的时候发现一类数非常有趣,他们和杠杆有比较相似的结构。这类数有这样的性质:
把某一位当成支点的话,那么左边的数字到这个点的力矩和等于右边的数字到这个点的力矩和,力矩可以理解为距离乘以数字。
举个例子,4139就是满足条件的数字,把3当成支点,我们有这样的等式4 * 2 + 1 *1 = 9 * 1。
小明想知道在一个区间[x,y]中,有多少个这样的数。
【输入数据】
两个数,表示x,y。 0 <= x,y<= 1018。
【输出数据】
一个输出,表示区间[x,y]中满足条件的数的个数。
【样例输入】
7604 24324
【样例输出】
897
【数据范围】
0 <= x,y<= 1018
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<functional> #include<algorithm> using namespace std; #define MAXS 810 + 10 +4000 #define MAXx 1000000000000000000 #define MAXI 30 long long f[MAXI][MAXS][2],depth,a[MAXI],ans,pos; //0 <= 只能取<=第i位的数,否则超过X越界 1 高位已经取了更小的 位数 后面随便取 long long dfs(int i,int s,int c) { if (s<0||s>MAXS) return 0; if ((i==0)&&((s)||(c))) return 0; if (i==0) {//cout<<i<<' '<<s<<' '<<c<<' '<<f[i][s][c]<<endl; return 1;} // cout<<i<<' '<<s<<' '<<c<<' '<<f[i][s][c]<<endl; if (f[i][s][c]>=0) return f[i][s][c]; else f[i][s][c]=0; if (!c) { // cout<<"push "<<a[i]<<endl; f[i][s][c]+=dfs(i-1,s-(pos-i)*a[i],0); } else { for (int k=0;k<a[i];k++) //{ cout<<"push "<<k<<endl; f[i][s][c]+=dfs(i-1,s-(pos-i)*k,0); // cout<<"pop "<<k<<endl;} for (int k=0;k<=9;k++)//{ cout<<"push "<<k<<endl; f[i][s][c]+=dfs(i-1,s-(pos-i)*k,1); //cout<<"pop "<<k<<endl;} } return f[i][s][c]; } long long calc(long long x) { if (!x) return 0; //<0的杠杆数为0 long long ans=0; memset(f,0,sizeof(f)); depth=0; while (x) { depth++; a[depth]=x%10; x=x/10; } for (int i=1;i<=depth/2;i++) { swap(a[i],a[depth-i+1]); } ans=0; f[depth+1][0][0]=1; // =29333 f[depth+1][0][1]=1; // <29333 for (pos=1;pos<=depth;pos++) { memset(f,128,sizeof(f)); // cout<<f[19][0][0]<<endl; ans+=/*dfs(depth,0,0)+*/dfs(depth,0,1); ans--; //不考虑 0 它无论支点为几都出现 } return ans+1; //最后 加上 0 /* f[i][s][c]=f[i-1][s-(k-i)*j][0] */ } int main() { freopen("number.in","r",stdin); freopen("number.out","w",stdout); long long x,y; scanf("%lld%lld",&x,&y); printf("%lld",calc(y+1)-calc(x)); // while (1); }