用于辅助备战第十届的同学
A.G1024(*800)
考查:暴力
分析:对每趟列车剩余的票数求和,注意不要忘了票不够输出“G!
Code:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,k,x,y;
int a[1010];
cin>>n>>k;
for(int i=1;i<=k;i++)
{
cin>>x>>y;
a[i]=y-x;
}
int sum=0;
for(int i=1;i<=k;i++)
{
sum+=a[i];
if(sum>=n)
{
cout<<i;
return 0;
}
}
cout<<"G!";
}
B.NEUQ(*800)
考查:字符串
分析:我们从左到右遍历字符串,对"NEUQ"依次进行匹配,用ans记录成功匹配的次数。如果正好匹配到NEUQ的最后一位,答案就是n-ans;如果没匹配完,还需要考虑匹配到一半的字符串。
Code:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin>>n;
string str="NEUQ";
string s;
cin>>s;
int cnt=0,ans=0;
for(int i=0;i<n;i++)
{
if(cnt==4) cnt=0;
if(s[i]==str[cnt])
{
ans++;
cnt++;
}
}
if(cnt==4) cnt=0;
cout<<n-ans+cnt;
}
C.小G的任务(*800)
考查:暴力
分析:对1~n的数求各位数字加和的加和(),n<=1000000,直接暴力求不会超时
Code:
#include<bits/stdc++.h>
using namespace std;
int f(int x)
{
int sum=0;
while(x)
{
sum+=x%10;
x/=10;
}
return sum;
}
int main()
{
int n;
cin>>n;
long long sum=0;
for(int i=1;i<=n;i++) sum+=f(i);
cout<<sum;
}
D.nn与游戏(*1100)
考查:BFS
分析:对于每个控制单位而言,其它的控制单位和除了自己对应的敌对单位都是障碍物,所以对于每组单位坐标输入,我们需要先记录所有单位的位置,然后一一处理每个单位(只有10组,不用担心超时)。用vis数组先将所有的单位进行标记,对某一组单位进行处理时,只需要将其对应的敌对单位取消标记,然后BFS即可。处理下一组单位时重复上述操作。陷阱在地图上是永远存在的,对于陷阱直接在地图上标记即可。
Code:
#include<bits/stdc++.h>
using namespace std;
int dirx[4]={-1,0,1,0},diry[4]={0,1,0,-1};
struct node{int x,y,dis;};
struct trap{int x,y;};
struct query{int dx,dy,zx,zy;}q[11];
int n,m,t;
char s[1010][1010];
int vis[1010][1010];
bool check(int x,int y)
{
if(x<0||x>=n||y<0||y>=n||s[x][y]=='#'||vis[x][y]) return false;
return true;
}
int bfs(int dx,int dy,int zx,int zy)
{
queue<node>q;
node start,next;
start.x=dx,start.y=dy,start.dis=0;
vis[dx][dy]=1;
q.push(start);
while(!q.empty())
{
start=q.front();
q.pop();
for(int i=0;i<4;i++)
{
next.x=start.x+dirx[i];
next.y=start.y+diry[i];
if(check(next.x,next.y))
{
next.dis=start.dis+1;
if(next.x==zx&&next.y==zy) return next.dis;
vis[next.x][next.y]=1;
q.push(next);
}
}
}
return -1;
}
int main()
{
cin>>n>>m;
memset(s,'.',sizeof(s));
while(m--)
{
trap tr;
cin>>tr.x>>tr.y;
s[tr.x][tr.y]='#';
}
cin>>t;
for(int i=0;i<t;i++)
cin>>q[i].dx>>q[i].dy>>q[i].zx>>q[i].zy;
for(int i=0;i<t;i++)
{
memset(vis,0,sizeof(vis));
for(int j=0;j<t;j++)
{
vis[q[j].dx][q[j].dy]=1;
vis[q[j].zx][q[j].zy]=1;
}
vis[q[i].zx][q[i].zy]=0;
cout<<bfs(q[i].dx,q[i].dy,q[i].zx,q[i].zy)<<'\n';
}
}
E.第二大数(*900)
考查:暴力
题意:先从下标1开始,求a1~a2之间第二大的数,然后求a1~a3之间第二大的数......依次类推到a1~an;然后从下标2开始,求a2~a3之间第二大的数......最后是求an-1~an之间第二大的数。对这些第二大数进行求和。
分析:这道题N的范围为10000,可以尝试用暴力的方法过。在下标区间[i,j-1]之间,有最大值maxx和第二大数se,如果aj>maxx,那么最大值就变成了aj,maxx就变成了第二大数;如果aj<maxx但aj>se,那么aj就变成了第二大数。按照这种方式持续更新最大值和第二大数即可。
Code:
#include<bits/stdc++.h>
using namespace std;
int a[10010];
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
long long sum=0;
for(int i=1;i<n;i++)
{
int maxx=a[i],se=0;
if(a[i+1]>a[i])
{
maxx=a[i+1];
se=a[i];
}
else
{
maxx=a[i];
se=a[i+1];
}
for(int j=i+1;j<=n;j++)
{
if(a[j]>maxx)
{
se=maxx;
maxx=a[j];
}
else if(a[j]<maxx&&a[j]>se) se=a[j];
sum+=se;
}
}
cout<<sum;
}
F.Num(*1000)
考查:数学
分析:对于等式N=a*b+a+b,左右两边加1,就变成了N+1=a*b+a+b+1=(a+1)*(b+1),即要判断N是否满足条件,我们需要找一个大于1的数i(因为a>0,b>0),使(N+1)%i=0,即判断N+1是否是质数。(注意N=3需要特判)
Code:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin>>n;
if(n==1||n==2) cout<<"No";
else if(n==3) cout<<"Yes";
else
{
int flag=0;
for(int i=2;i<n;i++)
{
if((n+1)%i==0)
{
flag=1;
break;
}
}
if(flag) cout<<"Yes";
else cout<<"No";
}
}
G.特征值(*1000)
考查:前缀和
题意:假设给定一个数为1225,我们需要求出1225+122+12+1;对于99999,我们需要求出99999+9999+999+99+9
分析:数据范围极大,但是用字符串表示数却刚刚好。观察上述的计算过程,我们可以发现,计算的特点是每一个加数都是各位数字的前缀和。因此,我们将整个字符串转化成数字后求前缀和,再进行加法竖式运算模拟即可。
下面以字符串"1225"举例,前缀和数组为s[N]
1 2 2 5 第4位:(5+2+2+1)%10=s[4]%10=0,进位add=s[4]/10=1
1 2 2 第3位:(2+2+1+add)%10=(s[3]+add)%10=6,进位add=(s[3]+add)/10=0
1 2 第2位:(2+1+add)%10=(s[2]+add)%10=3,进位add=(s[2]+add)/10=0
+ 1 第1位:(1+add)%10=(s[1]+add)%10=1,进位add=(s[1]+add)/10=0
———— 由于add=0,说明最后第1位不需要进位
1 3 6 0 如果add>0,还需要在第1位之前填充上add
Code:
#include<bits/stdc++.h>
using namespace std;
int main()
{
string s;
int a[500010];
cin>>s;
int n=s.length();
a[0]=0;
for(int i=1;i<=n;i++) a[i]=a[i-1]+s[i-1]-'0';
stack<int>stk;
int add=0;
for(int i=n;i;i--)
{
stk.push((a[i]+add)%10);
add=(a[i]+add)/10;
}
if(add) stk.push(add);
while(!stk.empty())
{
cout<<stk.top();
stk.pop();
}
}
H.最大公因数(*1000)
考查:思维
题意:给出一个序列,你可以选择两个数,令其中一个数减去1,另一个数加1,可以无限次操作。问你最多能得到多少个不同的整个序列的最大公因数。
分析:本题的特点是,选择L和R的时候,不必令L<=R;无论怎么变换,数列的总和不变;规定任何正整数都是0的公因数。假设有n个加和为sum的数,我们可以把前n-2个数全变成0,只对最后两个数进行操作。操作时我们可以发现,当其中一个数是sum的因子时,它也是两个数的最大公因数(假设两个正整数a和b,如果a为sum的因子,那么存在一个正整数N,使得a*N=sum,b=sum-a=a*(N-1),a和b的最大公因数便是a,更严谨的证明可以看官方题解)。因此,答案就是sum的因子数。
Code:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,sum=0,a[1010],ans=0;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum+=a[i];
}
for(int i=1;i<=sum;i++)
if(sum%i==0) ans++;
cout<<ans;
}
I.玄神的字符串(*1100)
考查:贪心
分析:删除的规则与位置无关,只与0和1的数量有关。操作3不能删除字符,因此操作3是为操作1和2服务的。由于字符串长度为偶数,因此只有两种情况:0和1的数量都是偶数,或者都是奇数。假设0的数量x少于1的数量y:
(1)x和y是偶数
如果主要进行操作1:
方案1:先一直进行操作1,对于剩下的偶数数量的1,先将其中的一半变成0后再用操作1,花费:
方案2:先一直进行操作1,对于剩下的1全部执行操作2
如果主要进行操作2:
方案1:一直选择两个相同的字符一起删,花费:
方案2:先删x个0和x个1,将剩下一半数量的1变成0后,用操作1,花费:
(2)x和y是奇数
如果主要进行操作2:
方案1:先一直进行操作2,最后一定会剩下"01",对其之间进行操作1,花费:
方案2:先一直进行操作2,对剩下的01先变换一个数,再执行操作2,花费:
如果主要进行操作1:
方案1:先一直进行操作1,最后一定剩下偶数个1,对其全部进行操作2,花费:
方案2:先一直进行操作,将剩下一半的1变换后执行操作1,花费:
如果1的数量大于等于0的话也是同理。
针对不同的情况对上述四种花费取最小值即可。
Code:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int ans[4];
int cnt=0,cnt1=0;
string s;
int a,b,c;
cin>>s;
cin>>a>>b>>c;
int n=s.length();
for(int i=0;i<n;i++)
if(s[i]=='0') cnt++;
else cnt1++;
if(cnt%2==0)
{
ans[0]=n*b/2;
ans[1]=(max(cnt,cnt1)-min(cnt,cnt1))*(a+c)/2+min(cnt,cnt1)*b;
ans[2]=min(cnt,cnt1)*a+(max(cnt,cnt1)-min(cnt,cnt1))*(a+c)/2;
ans[3]=min(cnt,cnt1)*a+(max(cnt,cnt1)-min(cnt,cnt1))*b/2;
}
else
{
ans[0]=(n-2)*b/2+a;
ans[1]=(n-2)*b/2+c+b;
ans[2]=min(cnt,cnt1)*a+(max(cnt,cnt1)-min(cnt,cnt1))*(a+c)/2;
ans[3]=min(cnt,cnt1)*a+(max(cnt,cnt1)-min(cnt,cnt1))*b/2;
}
sort(ans,ans+4);
cout<<ans[0];
}
J.金牌厨师(*1600)
考查:二分答案
后续更新
K.WireConnection(*1400)
考查:最小生成树
分析:因为给出的是点坐标,因此我们需要将各个点连接的边进行存储,然后采用kruskal算法即可。
Code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2010;
int n,p[N];
int find(int x)
{
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
struct point{ll x,y,z;}points[N*N];
struct edge
{
int a,b;
ll w;
bool operator<(const edge &W)const
{
return w<W.w;
}
}edges[N*N];
double getdis(double x1,double y1,double z1,double x2,double y2,double z2)
{
return ceil(sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2)));
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>points[i].x>>points[i].y>>points[i].z;
int m=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(i!=j)
{
m++;
edges[m].a=i;
edges[m].b=j;
edges[m].w=getdis(points[i].x,points[i].y,points[i].z,points[j].x,points[j].y,points[j].z);
}
}
}
sort(edges+1,edges+m+1);
for(int i=1;i<=n;i++) p[i]=i;
ll res=0;
for(int i=1;i<=m;i++)
{
int a=edges[i].a,b=edges[i].b,w=edges[i].w;
a=find(a),b=find(b);
if(a!=b)
{
p[b]=a;
res+=w;
}
}
cout<<res;
}