A题
无坑点
#include <algorithm>
#include <iostream>
using namespace std;
const int MAXN = 1e6+100;
int main() {
int a,b,c,t,n;
cin>>t;
while(t--){
int sum=0;
cin>>a>>b>>c>>n;
sum=a+b+c+n;
if(sum%3==0){
if(a>sum/3||b>sum/3||c>sum/3) cout<<"NO"<<endl;
else cout<<"YES"<<endl;
}else cout<<"NO"<<endl;
}
return 0;
}
B题
一个机器人,只能向上或者向右走,要把地图中所有的口袋拿到,求最短路径,按照字典序排列输出路径。
- 我看这个这个数据范围不太大啊,为什么bfs就MLE了呢?一头扎进bfs心态崩了,如果有大佬用bfs做的还请留言指教。代码附上:
#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
const int MAXN = 1005;
int Data[MAXN][MAXN];
int r,d;
struct st{
string s;
int step;
int num;
int x,y;
};
int xx[]={
1,0};
int yy[]={
0,1};
int n;
void bfs(){
queue<st> q;
st now,Next;
now.x=0;
now.y=0;
now.step=0;
now.num=0;
q.push(now);
while(!q.empty()){
now=q.front();
q.pop();
for(int i=0;i<2;i++){
int dx=now.x+xx[i];
int dy=now.y+yy[i];
if(dx>r||dy>d) continue;
Next=now;
Next.x=dx;Next.y=dy;
Next.step++;
if(Data[dx][dy]) Next.num++;
if(i==0) Next.s.push_back('R');
else Next.s.push_back('U');
if(Next.num==n){
cout<<"YES"<<endl;
cout<<Next.s<<endl;
return;
}
q.push(Next);
}
}
cout<<"NO"<<endl;
}
int main() {
int t,x,y;
cin>>t;
while(t--){
cin>>n;
r=d=0;
for(int i=0;i<n;i++) {
cin>>x>>y;
Data[x][y]=1;
r=max(r,x);
d=max(d,y);
}
bfs();
memset(Data,0,sizeof Data);
}
return 0;
}
- 正解是贪心,因为只有两种情况把坐标按x排个序就好了。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <list>
using namespace std;
const int MAXN = 1e3+100;
int xx[]={
1,0};
int yy[]={
0,1};
struct node{
int x;
int y;
};
node d[MAXN];
bool cmp(node x,node y){
if(x.x==y.x) return x.y<y.y;
return x.x<y.x;
}
int main() {
int t,n,x,y;
cin>>t;
while(t--){
string s="";
bool flag=1;
cin>>n;
d[0].x=0;d[0].y=0;
for(int i=1;i<=n;i++){
cin>>x>>y;
d[i].x=x;
d[i].y=y;
}sort(d,d+n+1,cmp);
for(int i=0;i<n;i++){
if(d[i].y>d[i+1].y) {
flag=0;
break;
}else{
for(int j=d[i].x;j<d[i+1].x;j++) s+='R';
for(int j=d[i].y;j<d[i+1].y;j++) s+='U';
}
}if(flag) {
cout<<"YES"<<endl;
cout<<s<<endl;
}
else cout<<"NO"<<endl;
}
return 0;
}
C题
无坑点
#include <algorithm>
#include <iostream>
#include <cmath>
using namespace std;
const int MAXN = 1e6+100;
int main() {
int t,n;
cin>>t;
while(t--){
cin>>n;
int tmp=pow(n,1.0/3);
bool flag=false;
for(int i=2;i<=tmp;i++){
if(n%i==0){
int c=sqrt(n/i);
for(int j=i+1;j<=c;j++){
int temp=i*j;
if(n%temp==0&&j!=n/temp&&i!=n/temp) {
cout<<"YES"<<endl;
cout<<i<<' '<<j<<' '<<n/i/j<<endl;
flag=true;
break;
}
}
if(flag) break;
}
}
if(!flag) cout<<"NO"<<endl;
}
return 0;
}
D题
碰到这题的第一感觉就是头大,但是题目看明白了也就不是太难了,怪我英文不好,但是这个题意真的让我理解了好久。
- 题意是这样的,先给定一个数x,然后每次都输入一个数,用这些数字去填充一个空的数组,每添加一个数就是一次询问,询问的是这个数组当前非负的、最小的,满足这两种情况的最大值。x的作用是可以对数组中任意的数进行加或者减操作(任意次),操作之后数组也将随之改变。
说实话读题比做题难多了。 - 查询、加减什么的让人总是往线段树那里去想,但是这个问题真的没有那么复杂,我们可以这样来考虑:因为问的是最小可能性中的最大值,那么0,1,2,3等等等等这些都是要被填充的,哪个没被填充答案就是哪一个,又因为都是模x所以可以把这些数字按照模x的余数去分类,放在一个数组中去存储,然后呢,输出答案肯定是递增的,所以可以递推出来。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <list>
using namespace std;
const int MAXN = 1e6+100;
int dp[MAXN];
int main() {
int q,x,n;
cin>>q>>x;
int ans=0;
for(int i=0;i<q;i++){
cin>>n;
dp[n%x]++;
while(dp[ans%x]){
dp[ans%x]--;
ans++;
}
cout<<ans<<endl;
}
return 0;
}
E题
给你一个二维数组可以进行两种操作,第一种是把某一个位置的数字改成任意数字,第二种是把某一列数字整体循环上移一个单位,也就是说第一个位置的挪到最后一个位置第二个位置到第一个位置以此类推:
那么移动到下面这种状态需要最少多少步。
- 读懂题目意思是关键,乍一看好像八数码,直接want to die,但是仔细一看就这么两种操作,我们至少可以获取到这样几个信息:
1.设m行n列,大不了一个一个换,最多n*m步;
2.每次的操作不会涉及行与行之间的操作,肯定是列内部进行的某些操作,每一列最多移动m次。 - 这样就可以得到思路:枚举每列达到目标状态的最小步骤,然后全加起来应该就行。
- 最后注意一点:数据范围是m*n<=2×105。
#include <algorithm>
#include <iostream>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <list>
using namespace std;
const int MAXN = 1e3+100;
int main() {
int m,n;
cin>>n>>m;
int Data[n][m];
int Array[n];
for(int i=0;i<n;i++){
for(int j=0;j<m;j++) cin>>Data[i][j];
}
int ans=0;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++) Array[j]=0;
for(int j=0;j<n;j++){
if((Data[j][i]-1-i)%m==0&&Data[j][i]<=n*m){
int pos_right=(Data[j][i]-1)/m;//正确位置
int distance=j-pos_right;//需要移动多少步,正数就是向上,负数就是向下
if(distance<0) distance+=n;
Array[distance]++;//统计某个步数有多少数字
}
}
int INF=0x3f3f3f3f;
for(int j=0;j<n;j++) INF=min(INF,j+n-Array[j]);//枚举j次移动,该列所有元素达到目标状态的次数
//m-cnt[j]是不能通过移动达到目标状态的数字量,这些数字只能通过第一种操作来完成改变
ans+=INF;
}cout<<ans;
return 0;
}
树没学到,未完待续···