传送门:点击打开链接
A题:给定一个长度为n的序列。给定操作:删除除首尾元素以外的任何一个元素。得到一个新的序列。新序列相邻两个元素间的差。求每一次差的最大值的最小值样例已经给的很清楚了。
思路:数据量很小,直接暴力模拟,时间复杂度n*n。当然这道题方法很多。
AC代码
#include <bits/stdc++.h>
#define debug puts("xxxxxxx")
#define pi (acos(-1.0))
#define eps (1e-8)
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=100005;
int a[maxn];
int cha;
int main()
{
int i,j,n,mn=-inf,ans=inf;
cin>>n;
for(i=0;i<n;i++) cin>>a[i];
a[n]=-inf;
for(i=1;i<n-1;i++)
{
int pre=0,next=1,cnt=0;
mn=-inf;
while(next<n)
{
if(pre==i) pre++;
if(next==i) next++;
if(pre==next) next++;
//if(next==n) break;
cha=a[next]-a[pre];
mn=max(mn,cha);
pre++;
next++;
}
ans=min(ans,mn);
}
cout<<ans<<endl;
return 0;
}
题意:给定一个位数为n的数字。有以下两种操作。1:将每一位加1(9变成0)。2:将每一位右移(最右一位到最左)。可以得到很多新的数字。比较这些数字的大小(比较大小时忽略前导0),输出最小值。
思路:最小值必然是首位数字为0。由于数据量很小,因此,我们可以这样操作:枚举每一位,将该位变成0,然后将该位放到第一位。将所有结果保存在string类型数组中,按照字典序排序,输出字典序最小的即可。
AC代码
#include <bits/stdc++.h>
#define debug puts("xxxxxxx")
#define pi (acos(-1.0))
#define eps (1e-8)
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=1005;
int a[maxn],b[maxn];
string s[maxn];
char x[maxn];
int main()
{
int n,i,j,tmp;
cin>>n;
cin>>x;
for(i=0; i<n; i++) a[i]=x[i]-'0';
for(i=0; i<n; i++)
{
tmp=(9-a[i]+1) %10;
for(j=0; j<n; j++)
{
b[j]=a[j];
}
for(j=0; j<n; j++)
{
b[j]=(b[j]+tmp)%10;
}
int cnt=0;
while(cnt<n-1)
{
s[i]+=(b[(i+1+cnt)%n]+'0');
cnt++;
}
}
sort(s,s+n);
cout<<0;
cout<<s[0]<<endl;
return 0;
}
C题
题意:给定一个n*m的字符矩阵。给定操作:删除某些列,使得每一行比上一行的字典序大。求出最少操作次数。
思路:对于每一列,比较a[j+1]和a[j]的大小。如果a[j+1] > a[j],那么之后的列第j和第j+1行就不需要比较了。若a[j+1] < a[j],那么这一列就要删除。用一个vis数组标记每一行是否还需要判断。对于需要判断的判断即可。
AC代码
#include <bits/stdc++.h>
#define debug puts("xxxxxxx")
using namespace std;
typedef long long ll;
const int maxn=105;
char a[maxn][maxn],vis[maxn];
int n,m;
int main()
{
cin>>n>>m;
int i,j,ans=0;
for(i=0; i<n; i++) cin>>a[i];
int cnt=n-1;
memset(vis,0,sizeof(vis));
for(i=0; i<m; i++)
{
if(cnt==0) break;
int flag=0;
for(j=0;j<n-1;j++)
{
if(a[j][i]>a[j+1][i] && !vis[j])
{
ans++;
flag=1;
break;
}
}
if(!flag)
{
for(j=0;j<n-1;j++)
if(a[j][i]<a[j+1][i] && !vis[j]) vis[j]=1,cnt--;
}
}
cout<<ans<<endl;
return 0;
}
D题
题意:P和G两个人进行网球比赛。每一局有一个分数t,当一个人赢完s局时,比赛结束。每·没结束一局,双方比分清零。现在给定n个数,每个数可能是1或2。是1表示P赢1分,2表示G赢一分。那么问题来了,s和t的组合可能是哪些情况?
思路:枚举分数t,对于当前的t,模拟s。由于数据量较大,模拟时要用二分。
AC代码
#include <bits/stdc++.h>
#define debug puts("xxxxxxx")
#define inf 0x3f3f3f3f
typedef long long ll;
using namespace std;
const int maxn=100005;
int n,f[maxn][3];
pair<int,int> ans[maxn];
int get_pos(int pos,int k,int c)
{
int l=pos+1,r=n,m;
if(f[n][c] - f[pos][c] < k) return inf;
while(l<r)
{
m=(l+r) >> 1;
if(f[m][c]-f[pos][c]<k) l=m+1;
else r=m;
}
return l;
}
int get_ans(int k)
{
int pos=0,pos1=0,pos2=0,win1=0,win2=0,last;
while(true)
{
pos1=get_pos(pos,k,1);
pos2=get_pos(pos,k,2);
if(pos1>n && pos2>n) return -1;
if(pos1<pos2)
{
pos=pos1;
last=1;
win1++;
}
else if(pos1>pos2)
{
pos=pos2;
last=2;
win2++;
}
if(pos==n)
{
if(last==1 && win1<=win2) return -1;
if(last==2 && win2<=win1) return -1;
return max(win1,win2);
}
}
}
int main()
{
cin>>n;
int i,tmp;
memset(f,0,sizeof(f));
for(int i=1;i<=n;i++)
{
cin>>tmp;
f[i][tmp] = 1;
}
for(i=1;i<=n;i++)///到第i个1或者2的个数
{
f[i][1] += f[i-1][1] ;
f[i][2] += f[i-1][2] ;
}
int cnt=0;
for(i=1;i<=n;i++)
{
int res=get_ans(i);
if(res!=-1) ans[cnt++]=make_pair(res,i);
}
sort(ans,ans+cnt);
cout<<cnt<<endl;
for(i=0;i<cnt;i++)
cout<<ans[i].first<<" "<<ans[i].second<<endl;
return 0;
}