T1.特殊的正方形
![](https://img-blog.csdnimg.cn/img_convert/285dcfb8219101b75cd2bd199034e5d8.png)
思路:
模拟题
0.一开始没想到,感觉c++好像只能一行接着一行输出啊😶然后尝试找每一行符号的规律...嗯..没找出来,后来才发现其实可以先开矩阵再往里填东西的!!
先构建一个空的char矩阵,然后就转化成往这个矩阵里填对应的字符
然后就是从外到里一圈一圈填字符,总共填n-n/2次(不是n/2次)
写的时候注意下标
代码:
#include<bits/stdc++.h>
using namespace std;
int n;
char fil,ans[105][105];
int main()
{
//memset(ans,'#',sizeof(ans));
cin>>n;
int tot=n-n/2;//有几个圈,不是n/2!
for(int i=1;i<=tot;i++)
{
int stX=i,stY=i;
if(i%2!=0)fil='+';//奇数圈
else fil='.';
for(int j=stX;j<=n-2*(i-1)+stX-1;j++)ans[j][i]=fil;
for(int j=stX;j<=n-2*(i-1)+stX-1;j++)ans[j][n+1-i]=fil;//填充x
for(int j=stY;j<=n-2*(i-1)+stY-1;j++)ans[i][j]=fil;
for(int j=stY;j<=n-2*(i-1)+stY-1;j++)ans[n+1-i][j]=fil;//填充y
}//注意下标!!
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
cout<<ans[i][j];
cout<<endl;
}
}
T2.简单分数统计
![](https://img-blog.csdnimg.cn/img_convert/862d11efbde4ad1af92c17e5fa071b11.png)
思路:
模拟题,按着题目要求一步一步写就ok啦
代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,k,scoreT[205],score[205];
string id[205],nameT[205],isPass[205];
int main()
{
cin>>n>>m>>k;//n个人 m道题 k次提交
for(int i=1;i<=n;i++)cin>>id[i];
for(int i=1;i<=m;i++)cin>>nameT[i]>>scoreT[i];
for(int i=1;i<=k;i++)
{
string namet,ans;
bool flag=false;
int which;
string userID;
cin>>userID>>namet>>ans;
for(int j=1;j<=n;j++)
if(id[j]==userID)
{
flag=true;
which=j;
}
if(!flag)continue;
for(int j=1;j<=m;j++)
if(nameT[j]==namet)
if(ans=="AC")
score[which]+=scoreT[j];
}
for(int i=1;i<=n;i++)
cout<<id[i]<<' '<<score[i]<<endl;
}
T3.Alice的德州扑克
![](https://img-blog.csdnimg.cn/img_convert/5426a27b61eabc109b2513d316dc34b2.png)
思路:
也是模拟题,就是题目比较长
根据题目要求写出判断不同牌型的函数即可
比较讨厌的是葫芦的判定,用的方法是先选出两张同样花色的,再判断剩下三张花色是否相同
代码:
#include<bits/stdc++.h>//细节...注意一点😭
using namespace std;
int point[6],color[5];
bool same_color()
{
bool flag=true;
for(int i=1;i<5;i++)
if(color[i]!=color[i+1])
flag=false;
return flag;
}
bool increase()
{
bool flag=true;
for(int i=1;i<5;i++)
if(point[i]!=point[i+1]-1)
flag=false;
return flag;
}
bool ST()
{
bool flag=false;
for(int i=1;i<=5;i++)
{
int tot=0;
for(int j=1;j<=5;j++)
{
if(j==i)continue;
if(point[i]==point[j])
tot++;
}
if(tot>=3)
{
flag=true;
break;
}
}
return flag;
}
bool HL()
{
bool flag=false;
//先选两张点数相同的牌(2+3)
for(int i=1;i<=5;i++)
for(int j=1;j<=5;j++)
{
if(j==i)continue;
if(point[i]==point[j])//再看剩下三张
{
int p;
flag=true;
bool flag2=false;
for(int k=1;k<=5;k++)
{
if((k==i)||(k==j)||flag2==true)continue;
p=point[k];//选基准点
flag2=true;
}
for(int k=1;k<=5;k++)
{
if(k==i||k==j)continue;
if(point[k]!=p)
flag=false;
}
}
if(flag) return true;
}
return false;
}
int main()
{
for(int i=1;i<=5;i++)cin>>point[i];
for(int i=1;i<=5;i++)cin>>color[i];
if(same_color()&&increase()&&point[5]==14)cout<<"ROYAL FLUSH";
else if(same_color()&&increase())cout<<"STRAIGHT FLUSH";
else if(ST())cout<<"FOUR OF A KIND";
else if(HL())cout<<"FULL HOUSE";
else if(same_color())cout<<"FLUSH";
else if(increase())cout<<"STRAIGHT";
else cout<<"FOLD";
}
T4.走路
![](https://img-blog.csdnimg.cn/img_convert/14f7be061871ffb097ae9046f75a957e.png)
思路:
p.s这题样例看了好久,后来才发现所谓能到达指的是最后到达的位置,不算中间经过的点
看到题目其实一开始想到的是dfs,搜索每一个可能走到的位置,然后就TEL了😭
考虑dp:
这里定义二维数组dp[i][j],表示第i步能否走到第j阶
由于第0步一定在第0阶位置,所以初始值为dp[0][0] = 1
关于状态转移方程:
第i步的状态可以通过第i-1步的状态推出来
如果第i-1步可以到第j阶,那么只需要在判断一下j+a[i]与j+b[i]是否小于m就可以确定能否到达了
代码(dp和dfs):
#include<bits/stdc++.h>
using namespace std;
int n,m,a[105],b[105],dp[105][100005];//dp[i][j]走了i步后,在第j个位置上
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i]>>b[i];
dp[0][0]=1;
for(int i=1;i<=n;i++)//第几步
for(int j=0;j<=m;j++)//遍历这一步可能走到的情况
{
if(dp[i-1][j]==1&&j+a[i]<=m)//根据上一步的位置判断
dp[i][j+a[i]]=1;
if(dp[i-1][j]==1&&j+b[i]<=m)
dp[i][j+b[i]]=1;
}
for(int i=0;i<=m;i++)
cout<<dp[n][i];
}
#include<bits/stdc++.h>
using namespace std;
int n,m,a[105],b[105],ans[100005];
void dfs(int now,int cnt)
{
if(cnt>n+1)
{
ans[now]=1;
return;
}
dfs(now+a[cnt],cnt+1);
dfs(now+b[cnt],cnt+1);
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i]>>b[i];
dfs(0,0);
for(int i=0;i<=m;i++)
cout<<ans[i];
}//TLE
T5.走楼梯2
![](https://img-blog.csdnimg.cn/img_convert/4171fb4d1acfb404b05c5729aed71418.png)
思路:
dp题
当站在第 k 阶时,要考虑三种情况:
一步一阶登上第 k 阶
一步两阶,且第一次是一步两阶
一步两阶,且连续两次是一步两阶
根据这三种情况就有三种不同的递推关系:
(1)当前走了1步,到达此处的方式不受限制
(2)当前走了2步,到达此处的方式不受限制
(3)当前走了4 步,所以我们只能通过走1 步的方式到达此处
代码:
#include<bits/stdc++.h>
using namespace std;
long long n,dp[55][3];//dp[i][j]现在在第n阶,最近的连续j步走了两阶
int main()
{
int n;
cin>>n;
dp[0][0]=1;
for(int i=0;i<=n;i++)//我为人人型递推
for(int j=0;j<=2;j++)
{
dp[i+1][0]+=dp[i][j];//这一步走1级台阶
if(j<2)dp[i+2][j+1]+=dp[i][j];//走两阶
}
cout<<dp[n][0]+dp[n][1]+dp[n][2];
}
T6.订单编号
![](https://img-blog.csdnimg.cn/img_convert/0450703ff4f4c8fadf138106e5e4545a.png)
思路:
没思路qwq...看了答案也不是很明白为啥
摘了一段大佬的评论:
这是一个套路题,这个题相当于是一个无限更新的题,
那么我们需要用固定的长度区间去来往里面添加元素,
我们可以把单点操作变成区间查询。我们可以利用set的自动排序来找,
但是插入区间时需要倒着插,因为正着插无法找到大于等于x的数,
例如刚开始时只有一个区间,他就根本查不到大于等于x的区间。
set用法:set排序遇到pair,lower_bound查的是set的first,
不会查second,除非first相等才会按照second来排。
查到的时候只需要观察是否在区间内即可,
(如果区间的最小值大于等于x就直接输出x,如果区间最小值大于x就输出区间最小值)
查到之后将该点去掉分成两个区间。插入pair时需要用insert,并且带上大括号{}。
代码:
#include<bits/stdc++.h>
using namespace std;
set<pair<int,int>>s;
int n;
void myinsert(int l,int r)
{
if(l>r)return;
else s.insert({r,l});
}
int main()
{
ios_base::sync_with_stdio(false);//
cin.tie(NULL);//硬砍了属于是
cin>>n;
s.insert({2e9,1});
for(int i=1;i<=n;i++)
{
int tmp;
cin>>tmp;
auto iter=s.lower_bound(make_pair(tmp,0));
if(iter->second<=tmp)
{
cout<<tmp<<' ';
myinsert(iter->second,tmp-1);
myinsert(tmp+1,iter->first);
s.erase(iter);
}
else
{
cout<<iter->second<<' ';
myinsert(iter->second+1,iter->first);
s.erase(iter);
}
}
}
T7.一个小整数
![](https://img-blog.csdnimg.cn/img_convert/cb0f2324f56977b855c6ed2419ef88bb.png)
思路(没写出来,看的别人题解www):
考虑四种情况:
1、数量最多的那个数,数量是其它数的总和还多1以上
2、数量最多的那个数,数量是其它数的总和还多1
3、数量最多的那个数,数量正好等于其它数的总和
4、数量最多的那个数,数量小于其它数的总和
(以下最多数量的数我们简称x,其它数量的数简称y)
如果是第一种情况,那么显然无论我们怎么样,必然会有相邻的数相同的情况出现,直接输出-1。
如果是第二种情况,那么第一个数只能是x,然后一个y,一个x这样交替放,并且末尾也会是这个最多数,即:xyxy……xyx。
如果是第三种情况,那么第一个数可以是x也可以是y,即:xyxy……xy或yxyx……yx这样子。
如果是第四种情况,我们可以随便摆,只要保证相邻数不相同即可。
情况分析完毕,我们开始想题:
我们每次先遍历一遍这十个数,计算一下数量最多的数和其它数量数总和的关系,然后我们根据关系来取数:
如果是第一种情况,我们直接输出-1结束程序即可;如果是第二种情况,我们第一个数只能是这个最多数量的数;如果是第三、四种情况,我们可以取这十个数中最小的那个数(不强迫选,那为了数最小,我们肯定要选小的数放在前面),但要注意不能和上一个数相同。而且对于第2、3、4种情况,如果这是我们取的第一个数,那么这个数不能是0,因为除了0本身我们不能有前导0(建议一开始特判一下只有一个0,其它数都没有的情况),如果我们必须要取0了,那也是输出-1。
取完一个数后,我们把那个数的个数-1,然后回到开头进行下一步。
数的总个数是2e4,我们每次取一个数要遍历一下这十个数,然后就可以根据情况判断了,总复杂度也才1e5。
代码:
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>
#define endl '\n'
#define int ll
typedef long long ll;
typedef pair<ll, ll>PII;
const int N = 1e6 + 50;
ll n, v[10];
bool dfs(vector<int>& res)
{
int sum = 0, mx = 0, ans = -1;
for (int i = 0; i < 10; i++)
{
sum += v[i];
if (v[i] > mx)
{
mx = v[i];
ans = i;
}
}
if (sum == 0)return true;
sum -= mx;
if (sum + 1 == mx)
{
if (ans == 0 && res.empty())
{
return false;
}
else
{
res.push_back(ans);
v[ans]--;
}
}
else if (sum + 1 < mx)
{
return false;
}
else
{
int u = res.size() == 0 ? 1 : 0;
int k = u == 1 ? -1 : res.back();
for (int i = u; i < 10; i++)
{
if (v[i] != 0 && i != k)
{
res.push_back(i);
v[i]--;
break;
}
}
}
return dfs(res);
}
signed main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int sum = 0;
for (int i = 0; i < 10; i++)
cin >> v[i], sum += v[i];
if (v[0] == 1 && sum == 1)
{
cout << 0 << endl;
return 0;
}
vector<int>res;
if (dfs(res))
{
if (res.empty())cout << -1;
else for (auto i : res)cout << i;
cout << endl;
}
else
{
cout << -1 << endl;
}
return 0;
}
T8.饿饿,饭饭
![](https://img-blog.csdnimg.cn/img_convert/e6e178c72d552c34ece64217cb25ddc1.png)
思路:
二分查找
看到k范围就知道普通的遍历肯定要超时,考虑二分答案
我们在不超过k的情况下能打多少轮饭,采取二分的方式确定。这样对于剩下的最后一轮,我们再进行模拟即可
注意函数形参和传入的实参以及全局变量定义时候的范围要一致,不然可能出现奇怪的错误(比如这题我就被判runtime error找了好久才发现)
代码:
#include<bits/stdc++.h>
using namespace std;
long long n,k,sum,preT,a[100005];
queue<long long>q;
long long calc(long long tot)//形参变量类型要对应!
{
long long cnt=0;
for(long long i=1;i<=n;i++)
if(a[i]<=tot) cnt+=a[i];
else cnt+=tot;
return cnt;
}
void binary_search()
{
long long l=0,r=1e14;
while(l<=r)
{
long long mid=(l+r)/2;
if(calc(mid)<=k)l=mid+1;
else r=mid-1;
}
preT=r;
}
int main()
{
cin>>n>>k;
for(long long i=1;i<=n;i++)
{
cin>>a[i];
sum+=a[i];
}
if(k>sum)
{
cout<<"-1";
return 0;
}
binary_search();//查找最后一轮前还能打几轮
k-=calc(preT);//先更新k(不然后面a[i]变了)
for(long long i=1;i<=n;i++)//初始化打完preT轮饭之后的队列
{
a[i]-=preT;
if(a[i]>0)q.push(i);
}
for(long long i=1;i<=k;i++)
{
long long tmp=q.front();
if(a[tmp]>0)a[tmp]--;
q.pop();
if(a[tmp]>0)q.push(tmp);
}
while(!q.empty())
{
cout<<q.front()<<' ';
q.pop();
}
}