一周15题。。。基本都是大水题,练练手速和YY思维的那种- -。。
第一周。。。
A:求N个数中出现次数最多的数:用一个数组记录数字出现的次数,因为数只有1K,所以统计完后,暴力去找最大的那个数是什么鬼,然后再暴力跑一遍,看看出现次数最多的那个数是不是唯一的就好了- -。
B:求N个数中唯一不相同的那个数 :sort 看最后两个数是否相同,相同输出第一个数,不同输出最后一个数,毕竟只有一个数不同嘛- -。
C:一个炉石一回合的模拟:会玩炉石的都会做。。。直接模拟一回合后当前的怪是否GG就好了。。。
D:- -统计N个数中超过6000的个数:233333333
前四道是浙江省省赛的一眼题。。。
E:给你N个数,求删掉其中一个数后,相邻两个数差的绝对值最小是多少:数不多,一个个删,一个个判,更新就好了。。。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
int a[105];
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
int res=999999;
for(int i=2;i<=n-1;i++)
{
int tmp=0;
for(int j=1;j<=i-2;j++)
{
tmp=max(tmp,a[j+1]-a[j]);
}
for(int j=i+1;j<n;j++)
{
tmp=max(tmp,a[j+1]-a[j]);
}
tmp=max(tmp,a[i+1]-a[i-1]);
res=min(res,tmp);
}
cout<<res<<endl;
return 0;
}
F:给你N位数,有两种操作,操作1是每位加1,操作2是循环右移1位,求最后可以得到的数最小是多少:简单贪心,每位先变成0,变0后在让0到循环至第一位,更新最小值即可,string写起来很方便,第i位循环右移一位变成了(i+j)%n
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
string s,ans;
int n;
int main()
{
cin>>n;
cin>>s;
ans=s;
for(int i=0;i<n;i++)
{
string temp;
int t=s[i]-'0';
for(int j=0;j<n;j++)
{
int p=(i+j)%n;
int k=(s[p]-'0'-t+10)%10;
temp.push_back(k+'0');
}
if(temp<ans)
ans=temp;
// cout<<ans<<endl;
}
cout<<ans<<endl;
return 0;
}
G:给你n行m列,问至少删除多少列,可以使得当前的串,满足行列字典序非递减:暴力枚举每一列的相邻两行的元素看字典序是否非递减,不是就删了标记之,否则标记当前列的两行合法,继续往下找下去。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
char s[105][105];
bool ok[105];
bool yes[105];
int n,m;
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)
{
cin>>s[i];
}
int res=0;
bool flag;
for(int i=0;i<m;i++)
{
flag=1;
memset(ok,0,sizeof(ok));
for(int j=0;j<n-1&&flag;j++)
{
if(yes[j])
{
continue;
}
if(s[j][i]>s[j+1][i])
{
flag=0;
res++;
break;
}
else if(s[j][i]<s[j+1][i])
{
ok[j]=1;
}
}
if(flag)
{
for(int j=0;j<n;j++)
{
if(ok[j])
{
yes[j]=1;
}
}
}
}
cout<<res<<endl;
return 0;
}
H:一个人可以条过一场电影的T分钟看第i+t分钟的电影,现在给了此人不得不看的n个区间,和一次跳跃的时间,问这个人看我不得不看的n个区间,至少要看多少分钟:如果当前时间+t<看的区间的电影,就一个劲的+t好了(不能超过某场电影的左区间),然后到了一场必须看的电影的时候,记录花的时间,并更新下一个时间的起点为当前电影结束时间+1即可。
I:给你N对字符串(每个字符串只会在N对中出现一次),然后给你m个查询,输出当前字符串对应的位置中两个字符串长度最短的,长度一样,输出字典序最小的:一个map<string,int>直接搞定,没对字符串对应的是当前位置i,然后记录一下i位置查询到后该输出哪个,输出就好。。。。
J:给你两个点,然后给你一个一次函数的abc三个系数,问这两个点是否位于这条直线的两侧:两个点带入直线方程,判断是否异号即可。。。
K:问两个人做一场CF,谁得分更高,直接套题目给的公式。。。
L:给你m对字符串,如果第i对字符串的第二个字符串和第j对字符串的第一个字符串相同,两者就合并:我的做法是开两个字符串数组记录当前存了哪些字符串,然后再输入第j对字符串后,从已有的字符串数组里面进行暴力匹配,如果发现匹配到了,更新就好了,聪明的猪猪同学用了并查集的思想来做,先把没对字符串合并,然后M对输进来之后,找只出现过一次的字符串(假设叫K串吧),并统计,然后再一重循环找只出现过一次的,然后看该字符串的根是否是是K串,如果是,输出K串和找到的这个字符串即可。的确也是个很好的想法,不过猪的代码一开始各种莫名其妙的BUG,帮她DEBUG了一个小时才把BUG全部弄完。。。
我的代码:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
int q;
string o[1005];
string n[1005];
int main()
{
cin>>q;
int cnt=0;
while(q--)
{
bool flag=0;
string s1,s2;
cin>>s1>>s2;
for(int i=0;i<cnt;i++)
{
if(n[i]==s1)
{
n[i]=s2;
flag=1;
break;
}
}
if(flag==0)
{
o[cnt]=s1;
n[cnt]=s2;
cnt++;
}
}
cout<<cnt<<endl;
for(int i=0;i<cnt;i++)
{
cout<<o[i]<<" "<<n[i]<<endl;
}
return 0;
}
猪的代码:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<queue>
#include<stack>
#include<map>
using namespace std;
int vis[5005],re[5005];
int scnt;
map<string,int> w;
int makset(string x)
{
if(w.count(x)==0)
{
w[x]=scnt;
scnt++;
}
return w[x];
}
struct word
{
char a[250],b[250];
int x,y;
}s[1005];
int _find(int x)
{
if(re[x]==x) return x;
else return re[x]=_find(re[x]);
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
w.clear();
int cnt=0;
scnt=0;
memset(vis,0,sizeof(vis));
for(int i=0;i<3000;i++)
re[i]=i;
for(int i=0;i<n;i++)
{
scanf("%s%s",s[i].a,s[i].b);
s[i].x=makset(s[i].a);
s[i].y=makset(s[i].b);
vis[s[i].x]++;
vis[s[i].y]++;
int p=_find(s[i].x);
int q=_find(s[i].y);
if(p!=q) re[q]=p;
}
for(int i=0;i<n;i++)
{
if(vis[s[i].x]==1) cnt++;
}
printf("%d\n",cnt);
for(int i=0;i<n;i++)
{
if(vis[s[i].x]==1)
{
for(int j=0;j<n;j++)
{
if(vis[s[j].y]==1&&re[s[j].y]==s[i].x)
{
printf("%s %s\n",s[i].a,s[j].b);
break;
}
}
}
}
}
return 0;
}
M:思维题,给你N个节点,编号0-N-1,然后给定每个节点的度和与该节点直接相邻的点编号的异或值,让你还原所有边,并告诉你这N个节点和边一定是树或者森林。
思路:用队列模拟,因为是树或者森林,所以肯定存在度为1的点,把度为1的节点全部放入队列,分别让度为1的点出队列,设为f,然后它所对应的异或的值,就是与它有边相连的节点t(毕竟度为1),然后更新t的度,再更新t所对应的节点的异或值,更新就是当前的异或值和f异或一次就OK啦,别问我为什么,那个异或的公式很显而易见啊- -。。。如果t的度也为1,就再次入队,不过要注意模拟的过程会出现度为0的情况,continue就好,否则会有自环产生,然后直到队列空了,就输出就好了。。思路清晰就很好写啦,一道不错的思维题呢- -。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
struct edge{
int from;
int to;
}a[1<<17];
int d[1<<17],xsum[1<<17];
int n;
queue<int> q;
int main()
{
cin>>n;
for(int i=0;i<n;i++)
{
cin>>d[i]>>xsum[i];
if(d[i]==1)
{
q.push(i);
}
}
int cnt=0;
while(!q.empty())
{
int f=q.front();
q.pop();
if(d[f]==0) continue;
int t=xsum[f];
a[cnt].from=f;
a[cnt].to=t;
cnt++;
d[t]--;
if(d[t]==1)
q.push(t);
xsum[t]^=f;
}
cout<<cnt<<endl;
for(int i=0;i<cnt;i++)
{
cout<<a[i].from<<" "<<a[i].to<<endl;
}
return 0;
}
N:输入输出练习,没啥说的23333333,注意一下奇偶就好。
O:判断是否有节点数大于等于4的环,定好一个起点dfs搜过去就好了,但是尼玛我定义的dx dy不同,答案就会有bug,现在都不知道是为啥,还有我dfs写起来真是要命QAQ。。。。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m;
char s[105][105];
bool vis[105][105];
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
bool flag=0;
void dfs(int x,int y,int xx,int yy)
{
for(int i=0;i<4;i++)
{
if(flag==1)
{
return ;
}
int _x=x+dx[i];
int _y=y+dy[i];
if(s[x][y]==s[_x][_y]&&_x>=0&&_x<n&&_y>=0&&_y<m&&vis[_x][_y]==1&&xx!=_x&&yy!=_y)
{
//cout<<_x<<" "<<_y<<endl;
cout<<"Yes"<<endl;
flag=1;
return ;
}
if(vis[_x][_y]==0)
{
if(s[x][y]==s[_x][_y]&&_x>=0&&_x<n&&_y>=0&&_y<m)
{
//cout<<_x<<" "<<_y<<endl;
vis[_x][_y]=1;
dfs(_x,_y,x,y);
}
}
}
}
int main()
{
cin>>n>>m;
flag=0;
memset(vis,0,sizeof(vis));
for(int i=0;i<n;i++)
{
cin>>s[i];
}
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(vis[i][j]==0&&flag==0)
{
dfs(i,j,i,j);
}
}
}
if(flag==0)
{
cout<<"No"<<endl;
}
return 0;
}
- -好好带一个小朋友,争取带出来,自己快要滚粗了,总得留下点什么给后人QAQ。。。