Day1
蓝桥杯模拟赛
A.带分数
题意大致是用[1,9]之间的数来构造一个带分数,而且[1,9]必须每个都出现一次
这不就是全排列吗?
1.我们可以用c++的stl函数,也可dfs深搜
2.将这个全排列函数分成三个部分,整数部分,分子部分,分母部分
3.不要求输出构造的函数,只要求输出结果总数ans
贪图省事的 Qinna用了最简单的库函数法。
方法一:net_permutation()函数
#include<bits/stdc++.h>
using namespace std;
int a[10]={0,1,2,3,4,5,6,7,8,9};
int make_num(int x,int y) //将下标为x~y的数字连成y-x位的整数
{
int sum=0;
for(int i=x;i<=y;i++)
sum=sum*10+a[i];
return sum;
}
int main()
{
int n,ans=0;
cin>>n;
do{
for(int i=1;i<=7;i++) //题目给出的范围10^6,整数最多6位
{
for(int j=i+1;j<=8;j++) //分子的数最多7位
{
int num1=make_num(1,i);//整数
int num2=make_num(i+1,j);//分子
int num3=make_num(j+1,9);//分母
if(num1+(num2/num3)==n&&(num2%num3==0))
ans++;
}
}
}while(next_permutation(a+1,a+10));
cout<<ans<<endl;
return 0;
}
B.错误票据
录入 ID 号的时候发生了一处错误,造成了某个 ID 断号,另外一个 ID 重号,找出断号的 ID 和重号的 ID。
这题不难,主要是要想到将所有数存起来……
有两种方法:
第一种稍显麻烦,需要考虑换行和空格
第二种虽然也需要考虑,但是很巧妙,因为输入一个数后面必然要跟着一个空格或者换行
Qinna太笨了,比赛的时候只想到第一种。
方法一:
#include<bits/stdc++.h>
using namespace std;
int a[100000] = {0};
int main(){
int n=0,pos=0;
cin>>n;
while(n--)
{
while(cin>>a[pos]) //用cin.get()吸收回车和换行
{
pos++;
if(cin.get()=='\n') //当cin.get()等于回车的时候读下一行数据
break;
}
}
sort(a,a+pos);
int re,cr;
for(int i = 0; i < pos; i++)
{
if(a[i] == a[i+1])
re= a[i];
else if(a[i+1]-a[i] == 2)
cr= a[i]+1;
}
cout<<cr<<" "<<re;
return 0;
}
方法二:
#include<bits/stdc++.h>
using namespace std;
int a[100000] = {0};
int main(){
int n=0,pos=0;
cin>>n;
while(cin>>m){ //读到结尾就自动结束了
a[pos++]=m;
}
sort(a,a+pos);
int re,cr;
for(int i = 0; i < pos; i++)
{
if(a[i] == a[i+1])
re= a[i];
else if(a[i+1]-a[i] == 2)
cr= a[i]+1;
}
cout<<cr<<" "<<re;
return 0;
}
C.翻硬币
每次只能同时翻转相邻的两个硬币,求最小操作步数。
找到不同的就翻这枚和下一枚就好
#include <bits/stdc++.h>
using namespace std;
string s1,s2;
int main()
{
cin>>s1>>s2;
int sum=0;
for(int i=0;i<s1.length()-1;i++)
{
if(s1[i]!=s2[i])
{
sum++;
s1[i]=s2[i];
if(s1[i+1]=='*')
s1[i+1]='o';
else
s1[i+1]='*';
}
}
cout<<sum<<endl;
}
D.灵能传输
古怪的题目,求max(s[i]-s[i-1])最小
1.前缀和
2.贪心
3.排序
这题愣是没搞懂怎么写,之前没了解过前缀和,因此只好把前缀和的代码奉上了
求[l,r]的和
#include<bits/stdc++.h>
using namespace std;
const long long N=100005;
long long a[N];
long long s[N];
long long m,n;
int main()
{
scanf("%lld%lld",&n,&m);
for(long long i=1;i<=n;i++) scanf("%lld",&a[i]);
for(long long i=1;i<=n;i++) s[i]=s[i-1]+a[i];
while(m--){
long long l,r;
scanf("%lld%lld",&l,&r);
printf("%lld\n",s[r]-s[l-1]);
}
return 0;
}
E.后缀表达式
首先我们得了解负号是可以相互抵消的,一个负号和很多个负号的效果其实是一样的
1.没有负号时,直接相加
2.有负号时:
可以表示成这样:
(……+……+……)-(……+……+……); //负号为奇数时
或者这样:
(……+……+……)-(……+……-……); //负号为偶数时
因此,只要最大的数-最小的数+其他数绝对值就OK
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN=1e5+10;
int n,m,k;
LL a[2*MAXN];
int main(){
scanf("%d%d",&n,&m);
k=n+m+1;
for(int i=1;i<=k;i++) scanf("%lld",&a[i]);
LL sum=0;
if(!m){
for(int i=1;i<=k;i++) sum+=a[i];
printf("%lld\n",sum);
return 0;
}
sort(a+1,a+k+1);
sum+=a[k];sum-=a[1];m--;
for(int i=2;i<k;i++) sum+=abs(a[i]);
printf("%lld\n",sum);
return 0;
}
F.等差数列
这题很具有迷惑性格,一开始我以为公差是最小的就好了,但是如果有四个数,差值为2,3。我们不能取2作为公差,因为中间无论插入什么数,都不能构成等差数列。
因此,正确的想法应该是求后面各项与第一项所有差值的最大公约数,这样能保证数列中的数最少,并且一定能构成等差数列。
最大公因数,也称最大公约数、最大公因子,指两个或多个整数共有约数中最大的一个。
例如:
2,3的最大公因数是1,因此公差为1
c++库函数中有个专门求最大公约数的函数__gcd()
#include<bits/stdc++.h>
using namespace std;
const int N=1000010;
int a[N];
int main(){
int n;
scanf("%d", &n);
for(int i = 0; i < n; i ++){
scanf("%d", &a[i]);
}
sort(a, a + n);
//求后面各项与第一项所有差值的最大公约数
int d = 0;
for(int i = 1; i<n;i++) d=__gcd(d,a[i]-a[0]);
if(!d) printf("%d\n", n);
else printf("%d\n", (a[n-1]-a[0])/d+1);
return 0;
}
G.特别数的和
直接按照题目要求把数给拆分判断就OK
#include <bits/stdc++.h>
using namespace std;
bool Is(int x){
int t;
while(x){
t=x%10;
if (t== 2||t==0||t==9||t==1) return true;
else x/=10;
}
return false;
}
int main(){
int n;
cin>>n;
int sum=0;
for(int i= 1;i<=n;++ i){
if(Is(i))
sum +=i;
}
cout<<sum<<endl;
return 0 ;
}
H.完全二叉树的权值
就是一个模拟题,一层一层的算。确定每一层的头和尾,记录深度。
#include<bits/stdc++.h>
using namespace std;
int a[100005];
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
int maxd=0;//记最大的那层深度为maxd
long long max=-100005;//记最大深度
//每层第一个数i是2的n次方
//每层最后一个数为下一层的前一个数。
int d=1;
for(int i=1;i<=n;i*=2,d++)
{
long long sum=0;
for(int j=i;j<=2*i-1&&j<=n;j++)
{
sum+=a[j];
}
if(sum>max) //找到最大的那层
{
max=sum;
maxd=d;
}
}
cout<<maxd<<endl;
}
Day2
二分法补题
分巧克力
每个小朋友至少1x1
输出切出的正方形巧克力最大可能的边长。
#include<bits/stdc++.h>
using namespace std;
int const N = 100010;
int w[N], h[N];//存储长、宽
int n, k;
bool chack(int a)
{
int num = 0;//记录分成长度为 a 的巧克力数量
for (int i = 0; i < n; i++)
{
num += (w[i] / a) * (h[i] / a);//每一大块可以分成的边长为 a 的巧克力数量
if (num >= k) return true;//大于要求数量,返回真
}
return false;
}
int main()
{
cin >> n >> k;
for (int i = 0; i < n; i++) cin >> h[i] >> w[i];
int l = 1, r = 1e5;//小巧克力数量边长一定在 1 -- 100000 之间
while (l < r)//二分小巧克力边长范围,找到符合要求的最大值
{
int mid = l + (r - l + 1 >> 1);//因为l = mid ,所以 mid 取 l + r + 1 >> 1,为了防止加和越界,改写成 l + (r - l + 1 >> 1)
if (chack(mid)) l = mid;
else r = mid - 1;
}
cout << r;
}
Day3
SMU Winter 2023 Round #1 (Div.2)~ACM
A.不可以,总司令
满足条件输出
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,y;
cin>>n>>y;
if(n>y){
cout<<"NO"<<endl;
}
else if(n<y){
cout<<"YES"<<endl;
}
else{
cout<<"equal probability"<<endl;
}
return 0;
}
B.计算
将三位数拆分
#include<bits/stdc++.h>
using namespace std;
int main()
{
long long n;
cin>>n;
long long ge,shi,bai;
ge=n%10;
bai=n/100;
shi=n/10%10;
long long sum1,sum2,sum3;
sum1=ge+shi+bai;
cout<<sum1<<endl;
sum2=sum1*sum1;
cout<<sum2<<endl;
sum3=sum1*sum1*sum1;
cout<<sum3<<endl;
return 0;
}
C.拱猪计分
考察细心和耐力的题目,写到吐血
发现一个很有用的库函数pair<T,T>,对付拱猪计分的那题非常有帮助
#include<bits/stdc++.h>
using namespace std;
char s[5];
const int shuzilue[16]={0,-50,-2,-3,-4,-5,-6,-7,-8,-9,-10,-20,-30,-40,-100,+100};
struct shabi
{
char fl;//花色
int shuzi;//数字
} f[5][21];
int sum[5];
int main()
{
while (1)
{
memset(f,0,sizeof(f));
memset(sum,0,sizeof(sum));
bool flag=true;//是否文件结束
for (int i=1;i<=4;i++)
{
int n;
scanf("%d",&n);
if (n!=0) flag=false;
for (int j=1;j<=n;j++)
{
scanf("%s",s); //字符串
f[i][j].fl=s[0]; //花色
f[i][j].shuzi=s[1]-48; //数字
if (strlen(s)==3)
f[i][j].shuzi=f[i][j].shuzi*10+s[2]-48;//最多两位数
if (f[i][j].fl=='C')
f[i][17].shuzi++;//花色数量
else if (f[i][j].fl=='S') f[i][18].shuzi++;
else if (f[i][j].fl=='D') f[i][19].shuzi++;
else f[i][20].shuzi++;
}
if (n==0) {sum[i]=0;continue;}//若未持有这 1616 张牌之任一张则以得零分计算
if (n==16) {sum[i]=1000;continue;}//若有一玩家持有所有 16 张计分牌,则得 +1000 分
if (f[i][20].shuzi==13) //全H
{
sum[i]+=200;
if (f[i][18].shuzi==1 && f[i][19].shuzi==1) sum[i]+=500;
else if (f[i][18].shuzi==1) sum[i]-=100;
else if (f[i][17].shuzi==1) sum[i]+=100;
}
else
for (int j=1;j<=n;j++) //普通牌
if (f[i][j].fl=='H') sum[i]+=shuzilue[f[i][j].shuzi];
else if (f[i][j].fl=='S') sum[i]+=shuzilue[14];
else if (f[i][j].fl=='D') sum[i]+=shuzilue[15];
if (n==1 && f[i][17].shuzi==1) sum[i]=50;//只有1张牌且是C牌
else if (f[i][17].shuzi==1) sum[i]*=2;//不只1张牌但是有C牌
}
if (flag)
return 0; //4个都是0
for (int i=1;i<=4;i++)
if (sum[i]>0) printf("+%d ",sum[i]);
else printf("%d ",sum[i]);
printf("\n");
}
return 0;
}
D.数字口袋
只要注意不要超过sum的最大值就好
#include<bits/stdc++.h>
using namespace std;
int main()
{
long long n;
cin>>n;
long long sum=0;
long long i=1;
while(sum<n){
sum=sum+i;
if(sum<=n){//一定要有这判断哇
cout<<i<<endl;
}
i++;
}
return 0;
}
E\F狠狠地切割(Easy\hard Version)
esay版本有两种解法,离散和二分,hard直接二分。
easy:
#include<bits/stdc++.h>
#define N 5000006
using namespace std;
int a[N],b[N],c[N];
bool iscut[N];
int main()
{
ios::sync_with_stdio(false);
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=m;i++) cin>>b[i];
for(int i=1;i<=m;i++)
c[b[i]]=1; //将b的值保存在c中
for(int i=1;i<=n;i++)
if(c[a[i]])
iscut[i]=true; //如果a中的值等于b,此点为割点,将下标值标记为true
iscut[0]=true; //a的头也是割点
int cnt=0;
for(int i=1;i<=n;i++)
if(!iscut[i]&&iscut[i-1])
cnt++;
cout<<cnt<<endl;
return 0;
}
hard:
#include<bits/stdc++.h>
using namespace std;
vector<long long>a,b;
int n,m;
bool check(long long k)
{
long long l=0,r=m-1,mid;
while(l<=r){
mid=(l+r)>>1;
if(k>b[mid]) l=mid+1;
else if(k<b[mid]) r=mid-1;
else return true; //找到
}
return false; //找不到
}
int main()
{
ios::sync_with_stdio(false);
cin>>n>>m;
long long x,y;
for(long long i=0;i<n;i++) cin>>x,a.push_back(x);
for(long long i=0;i<m;i++) cin>>y,b.push_back(y);
sort(b.begin(),b.end()); //vector的迭代器
long long ans=0;
if(!check(a[0])) //第一个数据不是断点,说明是个片段
ans++;
for(long long i=1;i<n;i++){
if(!check(a[i])&&check(a[i-1])) //这个数据不是断点,但是前一个数据是断点
ans++;
}
cout<<ans<<endl;
}
hard不用stl容器写法:
#include<bits/stdc++.h>
#define N 5000006
using namespace std;
int a[N],b[N],c[N];
bool iscut[N];
int main()
{
ios::sync_with_stdio(false);
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=m;i++) cin>>b[i];
for(int i=1;i<=m;i++)
c[b[i]]=1; //将b的值保存在c中
for(int i=1;i<=n;i++)
if(c[a[i]])
iscut[i]=true; //如果a中的值等于b,此点为割点,将下标值标记为true
iscut[0]=true; //a的头也是割点
int cnt=0;
for(int i=1;i<=n;i++)
if(!iscut[i]&&iscut[i-1])
cnt++;
cout<<cnt<<endl;
return 0;
}
另外,我发现stl可以快速解决去重的问题:
vector
sort(alls.begin(),alls.end()); //将所有值排序
alls.erase(unique(alls.begin(),alls.end()),alls.end()); //去掉重复元素
其中unique的作用时将所有重复元素放在数组的后面,并返回重复元素之前的最后一个数组下标,之后erase掉后面的重复元素就ok
G.如何得到npy
emmm实在是不好意思,写这题的时候我还不会图论和dfs,因此我不打算解这题,我把关于图论和dfs的知识先了解一波。
dfs代码:
dfs进行全排列
//DFS入门小题:打印全排列
#include<bits/stdc++.h>
using namespace std;
const int N=10000005;
int path[N];//存路径
bool st[N];//存状态
int n;//1~n的全排列
void dfs(int u){
if(u==n){
for(int i=0;i<n;i++)
printf("%d ",path[i]);
cout<<endl;
}
else{
for(int i=1;i<=n;i++){
if(!st[i]){ //没有记录过i
path[u]=i; //记录u这个位置可放的数
st[i]=true; //标记i被记录
dfs(u+1);//进入下一层
st[i]=false; //在这一层恢复现场
}
}
}
}
int main()
{
cin>>n;
dfs(0);//从0开始
return 0;
}
H.做不完的作业
有n个任务,每个有时间ti
Eric 前 i天要睡rxi小时,每天至少睡1小时,每天只能在做完所做的任务后睡觉。
问至少需要多少天才能完成任务。
那么我们可以 O(1) 求出完成这个任务需要先睡多少天,再完成任务即可
乐,,我还是没搞懂,直接复制大佬的代码,哭辽~
#include<bits/stdc++.h>
using namespace std;
long long n,x,p,q,i=1,sum,t,w;
int main(){
cin>>n>>x>>p>>q;
while(n--){
cin>>w;
if((x-t-w+sum)*q>=i*p*x&&x-t>w)t+=w;
else{
sum+=x-t;
i++;
long long l=ceil((q*(sum+x-w)-p*i*x)*1.0/(x*p-x*q));
if(l>0){
sum+=x*l;
i+=l;
}
t=w;
}
}
cout<<i;
}
I.毕业后
见代码
#include<bits/stdc++.h>
using namespace std;
//E每个学生最多拿到一个
//最大比例 ,向下取整floor()
int main()
{
double a,b; //a科目,b人数
cin>>a>>b;
double w;
w=1.0/a; //a种科目有一个为E的概率为1.0/a
w=floor(w*b)/b; //b学生中有一个科目为E的学生人数/b学生总人数
printf("%.16lf",w);
return 0;
}
J.旋转排列
将 p 里的每一个数字都依次向后移动一位,并把 p 的最后一个数字移动到开头去。
#include<bits/stdc++.h>
using namespace std;
vector<int>a;
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++){
int x;
cin>>x;
a.push_back(x);
}
while(1){
a.insert(a.begin(),a[n-1]);//头部插入
a.pop_back(); //尾部删除
for(int i=0;i<n;i++){
cout<<a[i]<<" ";
}
cout<<endl;
if(a[n-1]==n){
break;
}
}
return 0;
}
K.标题计数
数题解中有多少个一级标题
若一行的第一个非空白字符是井号(#),且紧跟着若干个空格,则这一行剩余的非空白内容将会按照一级标题渲染。
#include<bits/stdc++.h>
using namespace std;
int n,pos;
int main(){
cin>>n;
cin.get();
while(n--){
char a[1000];
fgets(a,1000,stdin); //读入一行数据
int f=0;
for(int i=0;a[i+1]!='\0';i++){
if(f==1&&a[i]!=' '){
pos++; //一级标题个数+1
break;
}//可能有首字符是空格的情况
if(a[i]!='#'&&a[i]!=' ') //不是一级标题,直接break
break;
if(a[i]=='#'){ //判断是不是一级标题
if(a[i+1]==' ')
f=1; //是标记为true
else
break; //不是直接break
}
}
}
cout<<pos;
return 0;
}
Day4
补题
用数组实现链表
#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
// e[i] 表示节点i的值
// ne[i] 表示节点i的next指针是多少
// cur 存储当前已经用到了哪个点
int cur=1,e[N],ne[N];
//注意:头结点为cur=0
void add_k(int k, int x) //将x插到第k个插入的元素后面
{
e[cur]=x; //将x值存入head之后的结点
ne[cur]=ne[k]; //将x结点指向k结点的下一个结点
ne[k]=cur; //将k结点的下一个结点指向x结点
cur++; //cur变到下一个位置
}
void del_k(int k) //删除第k个插入的元素后面的数
{
ne[k] = ne[ne[k]]; //k的下一个结点,指向k下一个结点的下一个结点。
//即掠过k的下一个结点
}
int main()
{
int m;
cin >> m;
while (m--) { //m组测试用例
char op;
int k,x;
cin >> op;
if (op == 'H') { //特殊判断,H的时候头结点cur=0
cin >> x;
add_k(0,x);
}
else if (op == 'I') { // 执行insert操作
cin >> k >> x;
add_k(k,x);
} else {
cin >> k;
del_k(k);
}
}
for (int j = ne[0]; j ; j = ne[j]) cout << e[j] << ' ';
cout << endl;
return 0;
}
Day5
SMU Winter 2023 Round #2 (Div.2)
A Medium Number
给三个数求中位数
1.可以排序之后取中间值
#include<bits/stdc++.h>
using namespace std;
int a[5];
int main()
{
int t;
cin>>t;
while(t--)
{
memset(a,0,sizeof(a));
for(int i=0;i<3;i++)
cin>>a[i];
sort(a,a+3);
cout<<a[1]<<endl;
}
return 0;
}
2.也可以直接无脑找出中间值、
#include <bits/stdc++.h>
using namespace std;
int main()
{
int t, a, b, c;
scanf("%d", &t);
while (scanf("%d%d%d", &a, &b, &c) != EOF)
{
if (a > b)
{
t = a; //b>a
a = b;
b = t;
}
if (a > c)//c>a
{
t = a;
a = c;
c = t;
}
if (b > c)//c>b
{
t = b;
b = c;
c = t;
}
printf("%d\n", b);
}
return 0;
}
B Yes-Yes?
用c++的stl寻找字串
#include<bits/stdc++.h>
using namespace std;
string s1;
int main(void)
{
int t;
cin >> t;
while(t--)
{
string s = "YesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYes";
cin >> s1;
if(s.find(s1)!=-1)
cout << "YES" << endl;
else
cout << "NO" << endl;
}
return 0;
}
C.Atilla's Favorite Problem
字符以'\0'为结束标志
特别记住:
小写字母-'a'=0~25
方法一:C风格的写法
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t,n,max;
scanf("%d ",&t);
while(t--)
{
max = 0;
scanf("%d ", &n);
int c;
while ((c=getchar())!= '\n') //用'\0'就用担心找不到结尾
{
if (max< c- 'a' + 1)
{
max= c- 'a' + 1;
}
}
printf("%d\n", max);
}
return 0;
}
方法二:C++风格的写法
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t,n,max;
scanf("%d ",&t);
while(t--)
{
max=0;
scanf("%d ",&n);
string s;
int a[100005];
cin>>s; //读入字符串
for(int i=0;i<s.size();i++)
a[i]=s.at(i)-'a'+1; //将字符串化成的数组赋值给整型数组
sort(a,a+s.size(),greater<int>()); //排序找最大的
printf("%d\n",a[0]); //输出最大
}
return 0;
}
D.Lost Permutation
全排列,先想到暴力bf
1.暴力的时候慢慢加都超过和,肯定不行
2.暴力完之后检查一遍,如果前面暴力枚举的数没有达到m+res个数,也就是说暴力枚举得到的数列个数不够,那也是没有完成全排列。
#include<bits/stdc++.h>
#define N 110
typedef long long ll;
using namespace std;
bool b[N];
int main(void)
{
int t;
cin >> t;
while(t--)
{
memset(b,0,sizeof(b));
ll m,s;
cin >> m >> s;
for(int i=1;i<=m;i++)
{
int num;
cin >> num;
b[num] = 1; //离散化
}
ll sum=0;
int flag=0;
int res=0;
for(int i=1;i<=N;i++) //bf
{
if(!b[i]) //当没有i这个数时
{
sum+=i;
res++; //记录bf添加多少个数
b[i] = 1;
}
if(sum==s) //正好等于和
{
break;
}
else if(sum>s) //大于和慢慢累加都不行你没救了
{
flag=1;
break;
}
}
for(int i=1;i<=m+res;i++)
{
if(!b[i]) //遍历一遍全排所有元素,看看是不是全排列
{
flag=1; //如果有一个没有被1的元素混入,说明前面bf没有枚举到他就已经超了或者等于s
break;
}
}
if(!flag)
cout << "YES" << endl;
else
cout << "NO" <<endl;
}
return 0;
}
E.Challenging Valleys
有坑点
1.只能有一个波谷,刚开始我以为题目判断的是有没有波谷,于是wrong on test 2
于是,我只能转换思路,判断是否只有一个波谷。
2.但是,没想到中间会有想通过的元素,于是判断左右两边是否存在波谷就显得蛮烦。
于是,当元素相同的时候直接把指针移向相同元素的后一位。
#include <bits/stdc++.h>
using namespace std;
long long a[200005];
int main(void)
{
int t;
cin >> t;
while(t--)
{
int n;
cin >> n;
for(int i=1;i<=n;i++)
{
cin >> a[i];
}
int cnt=0;
int l=1,r=1;//刚开始l和r相等
a[0] = 1e9+10; //为了不越界多围一圈
a[n+1] = 1e9+10; //左右边界一定满足,不论大小
for(int i=1;i<=n;i++)
{
//如果满足l小于左边,r小于右边,则是山谷,cnt++即可
if(a[l]<a[l-1]&&a[r]<a[r+1])
{
l = r+1;
r = l;
cnt++;
continue;
}
//如果r跟r+1相等,则证明它们是相同元素,所以r++
if(a[r]==a[r+1])
{
r++;
continue;
}
//保证左右仍然相等
l = r+1;
r = l;
}
if(cnt==1)
cout << "YES" << endl;
else
cout << "NO" << endl;
}
return 0;
}
F.Binary Inversions
本题只能改变一次:You are allowed to perform one operation on it at most once.
为了使0前面的1最多。
有两种改法:
1.将最前面的0改成1
2.将最后面的1改成0
本题还有一个坑点,也许改过之后的0前面的1不如不改的情况,所以要记得比较不改的情况。
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N = 2e5+10;
ll a[N],b[N],c[N];
int main(void)
{
int t;
cin >> t;
while(t--)
{
int n;
cin >> n;
for(int i=1;i<=n;i++)
{
cin >> a[i];
b[i] = a[i];
c[i] = a[i];
}
ll res=0;
for(int i=1;i<=n;i++)
{
if(a[i]==0) //0变成1
{
a[i] = 1;
break;
}
}
ll sum1=0,c1=0;
for(int i=1;i<=n;i++)
{
if(a[i]) //每个0前的1有几个
{
c1++;
}
else
{
sum1 += c1;//将第一个0改成1的sum
}
}
res = max(res,sum1);
for(int i=n;i>=1;i--)
{
if(b[i]) //1改为0
{
b[i] = 0;
break;
}
}
sum1=0,c1=0;
for(int i=1;i<=n;i++)
{
if(b[i])
{
c1++; //复制粘贴
}
else
{
sum1 += c1;
}
}
res = max(sum1,res);
sum1=0;
c1 = 0;
for(int i=1;i<=n;i++)
{
if(c[i]) //不变
{
c1++;
}
else
{
sum1 += c1;
}
}
res = max(sum1,res);
cout << res << endl;
}
return 0;
}
G.Quests
规则是这样的,你回答问题,你可以得到奖励,但是不能在k天内继续回答同一个问题。
1.如果某一天最大的奖励大于c。说明k无论取何值,都能满足奖励大于c->输出Infinity
2.如果所有天的最大奖励加起来都不大于c。说明k无论取何值,都不会满足奖励大于c->Impossible
3.用二分的方法,找出k。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll arr[200005];
bool check(int mid, ll c, int d, int n){
ll sum = arr[0];
for(int i = 1; i <= mid && i<min(d,n); i++){
sum += arr[i];
}
ll ans = d / (mid + 1); //运用倍数关系,直接将前面的循环步骤省略
int cnt = d % (mid + 1);
sum *= ans;
for(int i = 0; i < cnt && i < n; i++){
sum += arr[i];
}
if(sum >= c){
return true;
}
return false;
}
int main(){
int t;
cin >> t;
while(t--){
int n;
ll c;
int d;
cin >> n >> c >> d;
for(int i = 0; i < n; i++){
cin >> arr[i];
}
sort(arr, arr + n, greater<ll>());
ll sum = 0;
for(int i = 0; i < min(n, d); i++){
sum += arr[i];
}
if(sum >= c){
cout << "Infinity" << endl;
continue;
}
if(arr[0] * d < c){
cout << "Impossible" << endl;
continue;
}
int l = 0, r = max(d,n);
while(l <= r){
int mid = (l + r) / 2;
if(check(mid, c, d, n)){
l = mid + 1;
}else{
r = mid - 1;
}
}
cout << r << endl; //输出哪一边都ok
}
return 0;
}
H.SlavicG's Favorite Problem
emm由于dfs是真的不会,只能先放下这题去学深搜。。于是就把大佬的代码放上来
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<map>
#include<vector>
#include<queue>
using namespace std;
vector<pair<int,int>> p[100050];
int n,a,b;
int f = 0;
int dis[100050];
int vis[100050];
int dis1[100050];
int vis1[100050];
map<int,int> rr,ll;
void bfs()
{
queue<int> q;
q.push(a);
dis[a] = 0;
while(q.size())
{
auto ver = q.front();
q.pop();
if(vis[ver])
continue;
vis[ver] = 1;
for(int i = 0;i < p[ver].size();i++)
{
auto j = p[ver][i];
int ne = j.first;
int ww = j.second;
if(!vis[ne])
{
if(ne != b)
{
dis[ne] = ww^dis[ver];
q.push(ne);
}
}
}
}
}
void bfs1()
{
queue<int> q;
q.push(b);
dis1[b] = 0;
while(q.size())
{
auto ver = q.front();
q.pop();
if(vis1[ver])
continue;
vis1[ver] = 1;
for(int i = 0;i < p[ver].size();i++)
{
auto j = p[ver][i];
int ne = j.first;
int ww = j.second;
if(!vis1[ne])
{
dis1[ne] = ww^dis1[ver];
rr[dis1[ne]] = 1;
q.push(ne);
}
}
}
}
void solve()
{
f = 0;
cin >> n >> a >>b;
rr.clear();
ll.clear();
for(int i = 1;i <= n;i++)
{
p[i].clear();
vis[i] = 0;
dis[i] = 0;
vis1[i] = 0;
dis1[i] = 0;
}
for(int i = 1;i < n;i++)
{
int l,r,w;
cin >> l>>r>>w;
p[l].push_back({r,w});
p[r].push_back({l,w});
}
bfs();
bfs1();
for(int i = 1;i <= n;i++)
{
if(rr[dis[i]])
{
cout<<"YES\n";
return ;
}
}
cout<<"NO\n";
}
signed main()
{
int t = 1;
cin >> t;
while(t--)
{
solve();
}
}
I.The Humanoid
怪兽的血量越多越难吸收,所以要先从血量小的开始吸收,如果一个怪兽开始不可以被吸收了,后面的大血量怪兽都不可以被吸收。
我们可以发现一共就三瓶药,两种,我们把所有喝药的顺序情况枚举出来,找最大值即可
一、3,2,2
二、2,3,2
三、2,2,3
#include<bits/stdc++.h>
using namespace std;
long long a[200500];
void solve()
{
long long n,hh;
cin >> n >> hh;
for(int i = 0;i < n;i++)
cin >> a[i];
sort(a,a+n); //排序找最弱的人
int ans = 0;
//k=0,up=0 3,2,2
//k=1,up=0 2,3,2
//k=2,up=0 2,2,3
for(int k = 0;k <3;k++)
{
int up = 0;
int i = 0;
long long h = hh;
while(i < n)
{
if(h > a[i]) //h的血量大于人的血量
{
h += a[i]/2; //只能提升a[i]/2
i++;
}
else if(up == 3)
{
break;
}
else
{
if(up == k)
{
h = h*3;
}
else
{
h = h*2;
}
up++;
}
}
ans = max(ans,i); //吸收最多的人
}
cout<<ans<<"\n";
}
int main()
{
int t = 1;
cin >> t;
while(t--)
{
solve();
}
}
J.Make It Round
给定n,m,我们可以把n变为n×k(1<=k<=m,k为正整数),如果存在,请输出末尾0的个数最多的n×k,否则输出n×m。
为了出现0,我们需要有10,也就是2×5。
有几个0就是有多少个2×5
#include<bits/stdc++.h>
using namespace std;
char a[105][105];
void solve()
{
long long n,m;
cin >>n >> m;
int cnt2 = 0,cnt5 = 0;//记录5的个数和2的个数
int k = n;
while(k%2 == 0) //记录2的个数
{
cnt2 ++;
k = k/2;
}
while(k%5 == 0) //记录5的个数
{
cnt5 ++;
k = k /5;
}
while(cnt5 > cnt2&& m/2) //5的个数>2的个数,想办法在[1,m]中搞出2,凑成10
{
cnt5--;
n*=2;
m/=2;
}
while(cnt2 > cnt5&& m/5)//同理
{
cnt2--;
n *=5;
m/=5;
}
long long ans = 1;
while(ans*10 <= m)//找10的数目,找到不能找为止,当然,最后虽然可能不为10
{
ans = ans*10;
}
ans = m/ans*ans;
cout<<ans*n<<"\n"; //新的n已经保证为圆润的数了
}
int main()
{
int t = 1;
cin >> t;
while(t--)
{
solve();
}
}
K.Thermostat
见代码:
分三种情况
#include<bits/stdc++.h>
#define int long long
using namespace std;
int t;
int l,r;
int x,a,b;
signed main()
{
cin>>t;
while(t--)
{
int k=5; //k不会大于3
cin>>l>>r>>x>>a>>b;
if(a==b) //相同不用改变
{
cout<<0<<endl;
continue;
}
if(abs(a-b)>=x) //ab距离已经大于x,直接移到b
{
cout<<1<<endl;
continue;
}
if(abs(l-b)<x&&abs(r-b)<x) //b这个位置不能由两头到达,a不管怎么移动都到不了b
{
cout<<-1<<endl;
continue;
}
if(abs(l-a)>=x&&abs(l-b)>=x){
k=2;
}
else{
k=3;
}
if(abs(r-a)>=x&&abs(r-b)>=x){
k=2;
}
else{
k=k<3?k:3;
}
if(k>3)
{
cout<<-1<<endl;
}
else
{
cout<<k<<endl;
}
}
return 0;
}
L.Advantage
1.如果不是最大值,那就只能减去第最大
2.如果使最大值,那就减去第二大
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
ll t;
scanf("%lld",&t);
while(t--){
vector<ll>a,b;
ll n;
scanf("%lld",&n);
for(ll i=0;i<n;i++){
ll x;
scanf("%lld",&x);
a.push_back(x);
b.push_back(x);
}
sort(a.begin(),a.end(),greater<ll>());
for(ll i=0;i<n;i++){
if(b[i]!=a[0]) //不等于最大值,做差
printf("%d ",b[i]-a[0]);
else printf("%d ",b[i]-a[1]);//等于,减倒数第二大的
}
printf("\n");
}
}
标签:std,int,namespace,cin,long,寒假,2023,week0,include
From: https://www.cnblogs.com/Qinna-blogs/p/17023174.html