1、拼数
想到用string排序,但是自定函数中写的是a>b
这样会出现321>32但拼起来就不对的情况(应该是32321)
所以自定义函数中要用a+b>b+a
ps看题解的 妙啊
#include
#include
#include
using namespace std;
string str[30];
int comp(string a,string b){return a+b>b+a;}
int main()
{
int n;
while(cin>>n)
{
for(int i=0;i<n;i++)
{
cin>>str[i];
}
sort(str,str+n,comp);
string s="";
for(int i=0;i<n;i++)
{
s+=str[i];
}
cout<<s<<endl;
}
}
2、生日
stable_sort稳定输入:先输入的后输出,就可以不设置level
注意comp的写法
#include
#include
#include
using namespace std;
typedef struct node
{
string name;
int year;
int month;
int date;
}node;
node nod[105];
int n;
bool comp(node a,node b)
{
if(a.year!=b.year) return a.year<b.year;
if(a.year==b.year&&a.month!=b.month) return a.month<b.month;
if(a.month==b.month&&a.date!=b.date) return a.date<b.date;
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
{
cin>>nod[i].name;
cin>>nod[i].year;
cin>>nod[i].month;
cin>>nod[i].date;
}
stable_sort(nod,nod+n,comp);
for(int i=0;i<n;i++)
cout<<nod[i].name<<endl;
}
3、宇宙总统
因为输入是1~n,所以排序是到n+1;
#include
#include
#include
using namespace std;
int n;
typedef struct node
{
int number;
string str;
}node;
node s[25];
int comp(node a,node b)
{
if(a.str.size()!=b.str.size())
return a.str.size()>b.str.size();
else
return a.str>b.str;
}
int main()
{
while(cin>>n)
{
for(int i=1;i<=n;i++)
{
cin>>s[i].str;
s[i].number=i;
}
sort(s+1,s+n+1,comp);
cout<<s[1].number<<endl;
cout<<s[1].str<<endl;
}
}
4、明明的随机数
用set:自动去重,并且set中元素本就是排好序
注意迭代器的使用方法
#include
#include
using namespace std;
int main()
{
int n;
set<int> s;
cin>>n;
int temp;
for(int i=0;i<n;i++)
{
cin>>temp;
s.insert(temp);
}
set<int>::iterator it;
cout<<s.size()<<endl;
for(it=s.begin();it!=s.end();it++)
{
cout<<*it<<" ";
}
}
1、p1149-火柴棒等式
递归。
本来写的for循环只有1-9,然后发现错了,加数被加数和都是可以好多位的。然后就犯傻。其实从n<=24,可以推个大概的上限,就是到底可以几位数相加,所以我们把上限设置在1000.
也就是把本来for(int i=0;i<9;i++)改成for(int i=0;i<=1000;i++)就可以了。
而0~1000要用多少根火柴是可以通过递推算出来的。这里的递推看了题解,写得很巧妙——x[i]=x[i/10]+x[i%10]
AC代码:
#include
#include
using namespace std;
int dp[1005]={6,2,5,5,4,5,6,3,7,6};
vector<int> vec;
int n;
int ans=0;
void init()
{
for(int i=10;i<=1000;i++)
{
dp[i]=dp[i/10]+dp[i%10];
}
}
void dfs(int num,/*剩余火柴*/int index/*现在是1/2/3的第几个数字*/)
{
if(num==0&&index==3)
{
if(vec[0]+vec[1]==vec[2])
ans++;
return;
}
if(index>=3) return;
if(num<=0) return;
for(int i=0;i<=1000;i++)
{
vec.push_back(i);
dfs(num-dp[i],index+1);
vec.pop_back();
}
}
int main()
{
init();
while(cin>>n)
{
ans=0;
if(n<=10)
{
cout<<0<<endl;
break;
}
n=n-4;//减去加号和等于号
dfs(n,0);
cout<<ans<<endl;
}
}
2回文质数
玄学题解
1、因为回文数少,质数多。所以先判断回文,再判断质数。
2、偶数位的回文数一定不是质数(除了11)。因为偶数位的回文数一定是11的倍数——据说是小学数学,但我小学数学读不好 所以六位数和四位数的pass了。并且没有比9999999(7个)大的,我也不知道为什么,打个问号在这里了……
3、用printf,比较快
4、直接建数组int a[20],一开始用vector,有三个测试案例过不去。所以说vector耗时啊= =
ac代码:
#include
#include
#include
#include
using namespace std;
int check(int x)
{
if((x>=1000&&x<=9999)||(x>=100000&&x<=999999))
return 0;
else
return 1;
}
int judge(int n)//判断是不是质数
{
for(int i=2;i<=sqrt(n);i++)
{
if(n%i==0)
return 0;
}
return 1;
}
int hui(int x)//判断回文
{
int vec[20];int flag=1;
while(x!=0)
{
vec[flag]=x%10;
x=x/10;
flag++;
}
for(int i=1;i<=flag/2;i++)
{
if(vec[i]!=vec[flag-i])
return 0;
}
return 1;
}
int main()
{
int a;
int b;
while(cin>>a>>b)
{
b=min(9999999,b);
if(a%2==0) a++;
for(int i=a;i<=b;i=i+2)
{
if(!check(i)) continue;
if(!hui(i)) continue;
if(!judge(i)) continue;
printf("%d\n",i);
}
}
}
3、组合数
不难,但是题目要求“每个数字占三个位
用到iomanip里的setw
#include
#include
#include
#include
int vis[30];
using namespace std;
int n,r;
void dfs(vector<int> vec,int index,int cnt)
{
if(index==r)
{
for(int i=0;i<vec.size();i++)
{
cout<<setw(3)<<vec[i];
}
cout<<endl;
}
for(int i=cnt+1;i<=n;i++)
{
if(vis[i]==0)
{
vis[i]=1;
vec.push_back(i);
dfs(vec,index+1,i);
vec.pop_back();
vis[i]=0;
}
else
continue;
}
}
int main()
{
while(cin>>n>>r)
{
memset(vis,0,sizeof(vis));
vector<int> vec;
dfs(vec,0,0);
}
}
4、火星人
全排列函数(包含在algorithm头文件里):
如果是vector vec
next_permutation(vec.begin(),vec.end());
如果是数组int a[]
next_permutation(a,a+n)
注意是从当前开始全排列
#include
#include
#include
#include
#include
using namespace std;
int n,m;
int main()
{
vector<int> vec;
int temp;
while(cin>>n>>m)
{
for(int i=0;i<n;i++)
{
cin>>temp;
vec.push_back(temp);
}
for(int i=1;i<=m;i++)
{
next_permutation(vec.begin(),vec.end());
}
for(int i=0;i<n;i++)
{
if(i!=0) cout<<" ";
cout<<vec[i];
}
}
}
5栈
不用记忆化搜索会TLE
亲测
#include
using namespace std;
int f[20][20];
int n;
int dfs(int x,int y)//x是队列里的数,y是栈里的数
{
if(f[x][y]!=0) return f[x][y];
if(x==0) return 1;
f[x][y]+=dfs(x-1,y+1);//移到栈里
if(y>0) f[x][y]+=dfs(x,y-1);//从栈里pop
return f[x][y];
}
int main()
{
while(cin>>n)
{
dfs(n,0);
cout<<f[n][0]<<endl;
}
}
dp写法:
#include
#include
using namespace std;
int f[20][20];
int n;
int main()
{
while(cin>>n)
{
memset(f,0,sizeof(f));
for(int i=1;i<=n;i++)
{
f[0][i]=1;
}
for(int i=1;i<=n;i++)
{
for(int j=0;j<=n-i;j++)
{
f[i][j]+=f[i-1][j+1];
if(j>0) f[i][j]+=f[i][j-1];
}
}
cout<<f[n][0]<<endl;
}
}
6function
1、一开始修改了abc但是!注意输出的时候是要输出原来的abc的……
因为会RE所以如果abc其中有一个小于0就把他们都变成0
#include
#include
long long a,b,c;
int f[25][25][25]={0};
using namespace std;
long long w(long long a,long long b,long long c)
{
if(f[a][b][c]>0) return f[a][b][c];
if(a==0||b==0||c==0)
return f[a][b][c]=1;
else if(a<b&&b<c) return f[a][b][c]=w(a,b,c-1)+w(a,b-1,c-1)-w(a,b-1,c);
else return f[a][b][c]=w(a-1,b,c)+w(a-1,b-1,c)+w(a-1,b,c-1)-w(a-1,b-1,c-1);
}
int main()
{
while(cin>>a>>b>>c)
{
memset(f,0,sizeof(f));
if(a==-1&&b==-1&&c==-1) break;
cout<<"w("<<a<<", "<<b<<", "<<c<<") = ";
if(a<=0||b<=0||c<=0) {a=b=c=0;}
else if(a>20||b>20||c>20) {a=b=c=20;}
cout<<w(a,b,c)<<endl;
}
}
7、蜜蜂路线
dp+高精度
简单的dp,难在于要用高精度处理。
#include
using namespace std;
int dp[1005][600];//600存储高精度数字
int main()
{
int m,n;
while(cin>>m>>n)
{
memset(dp,0,sizeof(dp));
dp[m][0]=1;
dp[m+1][0]=1;
for(int i=m+2;i<=n;i++)
{
for(int j=0;j<600;j++)
{
dp[i][j]+=dp[i-1][j]+dp[i-2][j];
if(dp[i][j]>9)
{
dp[i][j]=dp[i][j]%10;
dp[i][j+1]++;
}
}
}
int flag=0;
for(int i=600;i>=0;i--)
{
if(flag==0&&dp[n][i]==0) continue;//flag标志位看是否到首位
else flag=1;
cout<<dp[n][i];
}
}
//类似题:数楼梯 但是这题要考虑n等于0的情况。注意!如果只有80分,可能是数组开的不够大。或者没考虑特殊情况。
8、小A点菜
一直在想怎么用记忆化搜索 其实剪枝就可以了……
dfs:
#include
using namespace std;
int n,m;
int price[105];
int ans=0;
void dfs(int index,int sum)
{
if(sum>m) return;//剪枝
if(sum==m) {
ans++;
return;
}
if(index==n) return;
for(int i=index;i<n;i++)
{
dfs(i+1,sum+price[i]);
}
}
int main()
{
while(cin>>n>>m)
{
ans=0;
for(int i=0;i<n;i++)
{
cin>>price[i];
}
dfs(0,0);
cout<<ans<<endl;
}
}
9、八皇后
经典回溯问题,设置三个数组用来判断列和两个对角线
#include
#include
using namespace std;
#define maxn 15
int visl[maxn*maxn];
int visx[maxn*maxn];
int visy[maxn*maxn];
vector<int> vec;
int ans=0;
int count=0;
int n;
void dfs(int x)
{
if(x>n)
{
ans++;
count++;
if(count<=3)
{
for(int i=0;i<vec.size();i++)
{
if(i!=0) cout<<" ";
cout<<vec[i];
}
cout<<endl;
}
return ;
}
for(int y=1;y<=n;y++)
{
if(visl[y]==0&&visx[x+y]==0&&visy[x-y+n]==0)
{
visl[y]=visx[x+y]=visy[x-y+n]=1;
vec.push_back(y);
dfs(x+1);
vec.pop_back();
visl[y]=visx[x+y]=visy[x-y+n]=0;
}
}
}
int main()
{
cin>>n;
dfs(1);
cout<<ans<<endl;
}
滑雪
记忆化搜索
#include
#include
using namespace std;
int dp[105][105];
int map[105][105];
int xt[4]={1,-1,0,0};
int yt[4]={0,0,1,-1};
int vis[105][105];
int n,m;
int dfs(int x,int y)
{
vis[x][y]=1;
if(dp[x][y]>1) return dp[x][y];
dp[x][y]=1;
for(int i=0;i<4;i++)
{
int xx=x+xt[i];
int yy=y+yt[i];
if((xx>0)&&(yy>0)&&(xx<=n)&&(yy<=m)&&(map[xx][yy]>map[x][y]))//可以往更高的地方爬
{
dp[x][y]=max(dp[x][y],dfs(xx,yy)+1);
}
}
return dp[x][y];
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>map[i][j];
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(vis[i][j]==0)
dfs(i,j);
}
}
int ans=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
ans=max(ans,dp[i][j]);
}
}
cout<<ans<<endl;
}
1、铺地毯
虽然题目只有一组数据,但是不用while(cin>>)循环输入就RE了T T
想法是用栈,最后覆盖上去的就是第一个出来的,符合坐标在里面的就可以
#include
#include
using namespace std;
int n;
typedef struct node{
int index;
int x;
int y;
int xlength;
int ylength;
}node;
int main()
{
while(cin>>n)
{
stack<node> s;
node temp;
int a;
int b;
for(int i=1;i<=n;i++)
{
temp.index=i;
cin>>temp.x;
cin>>temp.y;
cin>>temp.xlength;
cin>>temp.ylength;
s.push(temp);
}
cin>>a>>b;
int xmin,xmax,ymin,ymax;
int flag=0;
while(s.size()!=0)
{
temp=s.top();
s.pop();
xmin=temp.x;
ymin=temp.y;
xmax=temp.x+temp.xlength;
ymax=temp.y+temp.ylength;
if(a>=xmin&&a<=xmax&&b<=ymax&&b>=ymin)
{
cout<<temp.index<<endl;
flag=1;
break;
}
}
if(flag==0) cout<<-1<<endl;
}
}
2、均分纸牌
依然是看题解。
找到特殊的点:最左边和最右边——最左边只能通过右边移给它,也就是说它达到平均数以后就不用再动了。当第一张牌达到平均数,我们就直接剔除,然后看第二堆开始的后面的牌堆。
注意,在此时,我们并不关心,是先从第三堆以后的移到第二堆再给第一堆还是先给第一堆再从后面的补给,因为其实都是一样的。
而每个变成第一堆的第二三四五堆,只要是已经达到平均数的,都不用再动它,也就不用++ans。
#include
#define maxn 10005
using namespace std;
int n;
int a[maxn];
int main()
{
while(cin>>n)
{
int sum=0;
int ans=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum+=a[i];
}
int average=sum/n;
for(int i=1;i<n;i++)
{
if((a[i]-average)!=0)
{
a[i+1]+=a[i]-average;
ans++;
}
}
cout<<ans<<endl;
}
}
stl提供了堆,所以一般不用手写
priority_queue< int > 最大堆
priority_queue
求第k小的值
代码戳链接
这道题目就是用最小堆和最大堆两个堆来实现
合并果子
先取出最小的两堆合并成一堆,里面涉及哈夫曼树以及堆的使用,可以使权值最小。
priority:参数中greater< int>可以变成升序堆,每次都取最小的两个 priority_queue
#include
#include
using namespace std;
int main()
{
int n;
int temp;
while(cin>>n)
{
priority_queue<int,vector<int>,greater<int> > que;
for(int i=0;i<n;i++)
{
cin>>temp;
que.push(temp);
}
int a;
int b;
int ans=0;
for(int i=1;i<=n-1;i++)
{
a=que.top();que.pop();
b=que.top();que.pop();
temp=a+b;ans+=temp;que.push(temp);
}
cout<<ans<<endl;
}
}
铺设道路
和2013年的积木解题一模一样
#include
using namespace std;
#define maxn 100000
int a[maxn];
int main()
{
int n;
while(cin>>n)
{
int sum=0;
for(int i=0;i<n;i++)
cin>>a[i];
for(int i=1;i<n;i++)
{
if(a[i]>a[i-1])
{
sum+=a[i]-a[i-1];
}
}
sum+=a[0];
cout<<sum<<endl;
}
}
1、马的遍历 2、 3、字符串变换 约瑟夫问题-队列 木材仓库-集合 a-b数对-map 不重复数字-unordered_map 的定义与用法都与 map 差不多,只不过是用Hash来存储的,判断是O(1)的。所以判断来说比较快。 砍树 实数二分 1、模板 逆序 二叉树的深度遍历、宽度遍历二叉搜索树(待)、二叉平衡树。已知先序中序求后续遍历等一系列操作…… 一道链表模板题 差分与前缀和讲解 对照版本: 全部修改完再求和,用前缀和与差分。如果是边修改边求取,用线段树
bfs搜索,记录状态。
答案格式:左对齐五位:<#include
填涂颜色
为了防止最边角的0搜不到,在外面加一整圈0,从0~n+1开始#include
1、用map判断是否出现过这个字符串
如果是数字用 vis数组,如果是字符串,就用map
2、记住判断这个子串是否出现过以后,后面也有可能出现,所以要遍历直到find()超出字符串的范围
3、注意字符串的用法#include
数据结构(队列、集合、map)
如果取出的数刚好报m,扔掉,不然就放入队列中准备下一次报数#include
1、set的查找:find()
2、迭代器iterator 注意set中本就是排好位置顺序的
3、插入 insert()
4、判断是否为空empty();
5、删除:erase
set用法介绍#include
先用map记a[i]中的所有数,然后-c,在计算一遍#include
以及要用快读不然过不了#include
二分
#include
#include
ST表
用到了倍增#include
分治
其实就是归并排序,在排序中如果右半部分的先移下来但是左半部分的还有剩下就说明有逆序队。此时左半部分坐标i,那么逆序的个数就是mid-i+1#include
二叉树
二叉树题目+题解
链表
链表模板
差分与前缀和
铺地毯#include
#include
线段树
讲解+模板指路
线段树模板