题意:输入给出整数n,k,x,要求用任意数量的1-k中的数组成n,其中1-k中不能选择x
思路:其实就是分情况讨论,当x不为1的时候,则可以用n个1直接组成n,当x为1时再讨论k,如果k为1则无解,如果k为2,则只能用2,所以只能组合出偶数,如果k>=3,通过尝试枚举可以发现任何一个>1的数都可以仅有2和3来组成,如果为偶数则可以直接全用2,如果为奇数,则可以用一个3,剩余为偶数全2
ac代码:
#include<bits/stdc++.h> #define endl '\n' #define ll long long #define INF 0x3f3f3f3f #define pb push_back #define int long long #define Mirai ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); using namespace std; typedef pair<int,int> pii; const int N=1e6+10; int n,k,x; void solve() { cin>>n>>k>>x; if(x!=1) { cout<<"YES"<<endl; cout<<n<<endl; for(int i=0;i<n;i++)cout<<1<<" "; cout<<endl; } else { if(k==1)cout<<"NO"<<endl; else if(k==2) { if(n%2==0) { cout<<"YES"<<endl; cout<<n/2<<endl; for(int i=0;i<n/2;i++)cout<<2<<" "; cout<<endl; } else cout<<"NO"<<endl; } else { if(n==1)cout<<"NO"<<endl; else { cout<<"YES"<<endl; if(n%2==0) { cout<<n/2<<endl; for(int i=0;i<n/2;i++)cout<<2<<" "; cout<<endl; } else { cout<<(n-3)/2+1<<endl; cout<<3<<" "; n-=3; for(int i=0;i<n/2;i++)cout<<2<<" "; cout<<endl; } } } } } signed main() { Mirai; int T=1; cin>>T; while(T--) { solve(); } }
题意:输入给出一个起点的坐标以及两个终点的坐标,要求输出起点到两个终点的最小路径中的最大重合路径
思路:通过观察可以发现答案为起点到两个终点的曼哈顿距离之和减去两个终点的曼哈顿距离
ac代码:
#include<bits/stdc++.h> #define endl '\n' #define ll long long #define INF 0x3f3f3f3f #define pb push_back #define int long long #define Mirai ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); using namespace std; typedef pair<int,int> pii; const int N=1e6+10; struct Node { int x,y; }p[3]; int dist(Node a,Node b) { return abs(a.x-b.x)+abs(a.y-b.y)+1; } void solve() { for(int i=1;i<=3;i++)cin>>p[i].x>>p[i].y; cout<<(dist(p[1],p[2])+dist(p[1],p[3])-dist(p[2],p[3])+1)/2<<endl; } signed main() { Mirai; int T=1; cin>>T; while(T--) { solve(); } }
题意:输入给出字符串s,密码长度m以及密码上下限字符串l和r,要求找出一个长度为m的字符串,要求字符串不能为s的一个子序列,并且对于字符串的每一位,必须大于等于对应位置上的l和小于等于对应位置上的r
思路:由于密码最大只有10位,而每一位上的密码最多只有10种情况,所以可以枚举每一位密码然后到字符串中去对应寻找,我们在搜索某一位字符串时如果有一种情况没有搜索到就说明找到了合法情况,直接输出YES并返回即可,如果所有情况都搜到了,接下来进行下一位的密码搜索的时候只需要从当前位搜索到的最后一位的下一位开始搜索即可,具体原因见代码注释,只选择末尾位置的密码字符,保证了时间复杂度,每个位置上的密码只会向后延申一个分支,而不会每个选择都要对应之后搜索一遍
ac代码:
#include<iostream> #include<algorithm> #include<vector> #include<map> #include<unordered_map> #include<queue> #include<stack> #include<string> #define inf 0x3f3f3f3f #define PII pair<int,int> #define fi first #define se second #define ll long long using namespace std; //本题的重点在于找到一个密码串在s中不存在,而不是寻找存在的字符串,要注意理解这一点 //在搜完某一位密码之后,在进行后续搜索的时候,末尾位置的搜索区域最小 //并且这些搜索区域其他的位置的搜索区域也可以覆盖到,也就是说我们选取末尾位置的字符 //作为当前搜完的密码位上的字符,搜不到密码的概率最大,并且这样搜出的所有后续情况都是前面其他位置可以覆盖到的 //其他位上的密码字符进行后续搜索对于末尾位置的后续搜索是一个包含关系,情况只多不少 void solve() { int m; string s,l,r; cin >>s>>m>>l>>r; int cur=0; for(int i=0;i<m;i++) { int res=0; for(char j=l[i];j<=r[i];j++) { int tem=s.find(j,cur); if(tem==-1) { cout <<"YES"<<endl;return ; } tem++; res=max(tem,res); } cur=res; } cout <<"NO"<<endl; } int main(){ int t = 1; cin >>t; while(t--) { solve(); } return 0; }
题意:题目给出n个数字,要求以0开始,从左到右一直加到数组末尾,数组中存在负数,而此时可以设置一个整数k,当累计分数>=k之后,则分数最低为k,也就是说如果在减一个数之后即将<k时,则最多减到k,
思路:不难发现,这个数字k应该是一个在加上一个正数后即将加上一个负数的时候设置为当前分数值,也就是一个末尾为正数并且之后的第一个数为负数的前缀和,而在哪个边界加上k是接下来要思考的问题,设置的k要尽可能抵消掉多的减分,而不一定设置在第一个负数前,因为该负数后可能有数个正数导致这些正数之后的减分的不会被抵消,所以应该思考哪一个区间造成的减分最多,而在这个区间前设置k,注意此处不是寻找全负区间,而是总和为负数并且总和最小的区间,然后此区间前的数组前缀和即为答案
ac代码:
#include<bits/stdc++.h> #define endl '\n' #define ll long long #define INF 0x3f3f3f3f #define pb push_back #define int long long #define max(a, b) (((a) > (b)) ? (a) : (b)) #define min(a, b) (((a) < (b)) ? (a) : (b)) #define Mirai ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); using namespace std; typedef pair<int,int> pii; const int N=1e6+10; int n; int a[N],b[N]; void solve() { cin>>n; for(int i=1;i<=n;i++)cin>>a[i],b[i]=b[i-1]+a[i]; int res=0,premax=0,now=0; //res为最后结果 premax用来实时记录以当前位置结尾的最大前缀和 now用来记录得到的最小区间和 //这里同寻找最大区间异或和比较相同,对于以某一点结尾的前缀和减去在此之前的所有前缀和 //就可以得到从开头到当前点结尾的所有区间和,而我们要找最小区间和,并不关心是那一部分的区间和 //所以只需要记录一个最大的前缀和,然后直接相减就可以得到一个最小区间和 for(int i=1;i<=n;i++) { if(b[i]-premax<now) { now=b[i]-premax; res=premax; } premax=max(premax,b[i]); } cout<<res<<endl; } signed main() { Mirai; int T=1; cin>>T; while(T--) { solve(); } }