如果有写的不清楚的地方可以问我,或者群里的大佬们
目录
1001
1002(这题没人看吧)
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
?
1001
?关键信息:5位到6位的数,回文。
两种方法:
Plan A 先打一个回文数表,再循环10000-999999找到 各位和 等于n 的数,将其输出。
Plan B 先循环10000-999999找到 各位和 等于n 的数,再判断是否为回文数。
建议选择Plan B,比A快得多得多的多。
虽然我用了A也过了 ,但是
附上代码c++
#include<iostream>
#include<string>
#include<sstream>
using namespace std;
int x[1000010];
void huiwen()//回文数表
{
for(int i=10000;i<1000000;i++)
{
string a;
//string 容器,嫩好使的东西怎么能不用
//与字符数组使用有相似之处
ostringstream b;
b<<i;
a=b.str();
//c++中数字转字符串
//itoa为非标准数字转字符串 某些编译器可能不能用
//不喜欢就自己写个函数吧,奥利给
int l=a.size(),j;
//size()为a中元素个数
for(j=0;j<l/2;j++)//判断从前往后三位与从后往前三位是否相等
if(a[j]!=a[l-j-1])break;
if(j==l/2)x[i]=1;
}
}
int main()
{
huiwen();
int n;
bool f=0;
cin>>n;
for(int i=10000;i<1000000;i++)
{
int d=i,sum=0;
if(x[i]==0)continue;
//非回文数跳过
while(d)
{
sum+=d%10;
d/=10;
}
//计算各位和
if(sum==n)
{
cout<<i<<endl;
f=1;
}
}
if(!f)cout<<"-1"<<endl;
//如果没有输出-1
}
1002(这题没人看吧)
?关键信息:串并联概率,输出百分号
串联:全部相乘
并联:1-每个不能工作的概率相乘
附上代码c
#include<stdio.h>
#include<string.h>
int main()
{
int t;
char s[20];
int n;
scanf("%d",&t);
while(t--)
{
scanf("%s",s);
scanf("%d",&n);
double a,res=1;
if(strcmp(s,"parallel")==0)
//并联
for(int i=0;i<n;i++)
{
scanf("%lf%%",&a);
res*=(1-a/100);
if(i==n-1)
res=1-res;
}
else
//串联
for(int i=0;i<n;i++)
{
scanf("%lf%%",&a);
res*=a/100;
}
printf("%.2f%%\n",res*100);
}
}
1003
?关键信息:流量当月不清0
题意读取:假设上月留下的流量为 d ,本月流量优先使用本月套餐内流量,然后再使用 d。
附上代码c++(其实只有输入输出)
#include<iostream>
using namespace std;
int spend(int use,int yue,int yuemon,int d)
{
if(yue+d<use)
{
cout<<yuemon+(use-yue-d)<<endl;
d=0;
}
else if(use>yue)
{
cout<<yuemon<<endl;
d=0;
}
else
{
cout<<yuemon<<endl;
d=yue-use;
}
return d;
}
int main()
{
int yue,yuemon;//套餐流量与套餐价格
cin>>yue>>yuemon;
yue*=1024;
yuemon*=100;
int d=0;//上月留下的流量
int i=12;
while(i--)
{
int use;//本月使用流量
cin>>use;
d=spend(use,yue,yuemon,d);
//输出函数
}
}
1004
?烦人题
关键信息:非法地址输出 双冒号表示法 ,去除前导0
陷阱:a 双冒号只出现一次
? ? ? ? ? b 双冒号在头尾中间情况不同,以及只有双冒号的情况
本题使用函数将大幅度简化复杂度。
各位最好自己也了解一下
本题函数作用:
sscanf 用于从已读取的字符串中,读出需要内容
transform用于将小写字母转大写
附上代码c++
代码最后 寻找 0:0 与 :0:0解析
0:0有可能找到的是1000:0 此时不能删为100
而:0:0无法判断开头双冒号的情况
故两者结合 可以保证答案正确
c++的函数非常好用,反正我原来c写的时输出条件判断都绕晕了,有大佬愿意指导一下吗
#include<iostream>
#include<string>
#include<stdlib.h>
#include<sstream>
#include<algorithm>
#include<cctype>
using namespace std;
int main()
{
string s[8];
char c[100];
while(gets(c))//读取字符数组
{
int d[8],i;
string str(c);//将字符数组初始化给string
int l=str.size();//元素个数
for(i=0;i<l;i++)//判断地址是否合法
{
if(!((str[i]>='0'&&str[i]<='9')||(str[i]>='A'&&str[i]<='F')||str[i]==':'))
{
cout<<"It's not a IPv6 address!"<<endl;
break;
}
}
if(i<l)continue;
//相信你们已经看出来初始化string步骤有点多余。。。
sscanf(c,"%X:%X:%X:%X:%X:%X:%X:%X",&d[0],&d[1],&d[2],&d[3],&d[4],&d[5],&d[6],&d[7]);
//从字符数组中读出十六进制数
for(i=0;i<8;i++)
{
ostringstream p;
p<<hex<<d[i];
s[i]=p.str();
}
//转化16进制数存入s
//意义在于去除前导0
//注意,这里存入的字母是小写的
str=s[0];
for(i=1;i<8;i++)
{
str.push_back(':');//在尾部加:
str.append(s[i]);//在尾部连接字符串
//也可以写为str+=s[i];
//你问那为啥要用append?
//装13不行?
}
//将字符串连接
transform(str.begin(),str.end(),str.begin(),::toupper);
//这行用于将字母大写化
//string 的find:找到第一个出现的子串位置并返回
//若没有找到 返回-1
int x=str.find("0:0");
if(x!=-1&&(x==0||str[x-1]==':'))//特判以免出现1000:0的情况被误删
{
str.erase(x,3);//从x位置开始删除3个元素
while(x<str.size()&&str[x]==':'&&str[x+1]=='0')
str.erase(x,2);
if(x==str.size())str.insert(x,":");//如果位置在尾加:
if(x==0)str.insert(x,":");//如果位置在头加:
cout<<str<<endl;
}
else
{
x=str.find(":0:0");//出现1000:0的情况重新寻找
if(x==-1)//还是没找到输出-1
{
cout<<str<<endl;
continue;
}
str.erase(x+1,3);
while(x+1<str.size()&&str[x+1]==':'&&str[x+2]=='0')
str.erase(x+1,2);
if(x+1==str.size())str.insert(x+1,":");
if(x+1==0)str.insert(x+1,":");
cout<<str<<endl;
}
}
}
1005
?关键信息:位置改变规律?
你问我咋做,当然是找规律
此题==判断编号1何时重新回到位置1
为了看的明白点 将编号设为a 位置则用x表示
? ? ? ? x在前n位时,洗牌一次变为2x
? ? ? ? x在后n位时,洗牌一次变为(x-n)*2-1
用dowhile 和 条件分支语句即可完成
算法的事能叫猜吗
附上代码
#include<iostream>
using namespace std;
int main()
{
int n;
while(cin>>n)
{
int m=0,d=1;
do
{
if(d<=n)
d*=2;
else
d=(d-n)*2-1;
m++;//这是一个计数器
} while(d!=1);
cout<<m<<endl;
}
}
1006
?别说你复数运算不会。
关键信息: 最简输出
即
若 虚部为1或-1?则 1 i 和 -1 i 写为 i 和 -i
若 实部为0 虚部不为0 省略实部
若 虚部为0 省略0i
附上代码c
#include<stdio.h>
#include<string.h>
double a,b,x,y;
double sa,sb;
char s[2];
void suan()
{
//公式
//其实乘除也简单,但是调用函数不帅吗
if(s[0]=='*')
{
sa=a*x-b*y;
sb=a*y+b*x;
}
else
{
sa=(a*x+b*y)/(x*x+y*y);
sb=(b*x-a*y)/(x*x+y*y);
}
}
void put()
{
if(sa!=0)
{
printf("%.1f",sa);
if(sb>0)printf("+");
}
if(sb!=0)
{
if(sb!=1&&sb!=-1)
printf("%.1f",sb);
if(sb==-1)printf("-");
printf("i");
}
if(!sa&&!sb)printf("0.0");
printf("\n");
}
int main()
{
int n;
scanf("%d",&n);
while(n--)
{
scanf("%lf%lf%s%lf%lf",&a,&b,&s,&x,&y);
//加减较简单,直接干就完事
if(s[0]=='+')
{
sa=a+x;
sb=b+y;
}
else if(s[0]=='-')
{
sa=a-x;
sb=b-y;
}
else//调用乘除函数
suan();
put();//输出函数
}
}
1007
关键信息:复习一门课的最高效率值
纯纯水题?
找到最小即可得出答案
但是我用了一种比较cool的方法(反正估计没人看这题)
//自娱自乐
#include<iostream>
#include<queue>
#include<functional>
using namespace std;
int main()
{
int t;
int n,m;
cin>>t;
while(t--)
{
priority_queue<int,vector<int>,greater<int>> q;
//想不到吧
//优先队列 一手大炮打蚊子
//这里的用途 是 每存进去一个数会自动排序
//快去和你的同学们炫耀
//哎你这题咋写的
//啊你这就是逊哎 我可是用的优先队列
cin>>n>>m;
while(n--)
{
int d;
cin>>d;
q.push(d);
//存入队列且排序
}
cout<<(100-q.top())*(100-q.top())<<endl;
//队头即是最小值
}
}
1008
?关键信息:无
这有啥方法吗?
要说卡到我原因是我不会算利息(对 是我)
#include<iostream>
#include<stdio.h>
using namespace std;
int main()
{
int t,m;
double n,a,b,c,d,e,x;
cin>>t;
while(t--)
{
cin>>n>>a>>b>>c>>d>>e>>x>>m;
double q=a,w=e-n;
q*=x/100;
q*=12;
double p=12*m;
w*=x/100;
w*=p;
printf("%.2f %.2f %.2f %.2f\n",b,q+w,d,e-d-b-c-q);
}
}
1009
?关键信息:寻找最长回文子串,字符数不超过255
由于不超过255,暴力就行了
若是字符数较大,则要用 马拉车 算法,篇幅较长,详情自己了解
附上代码c
#include<stdio.h>
#include<string.h>
char s[300];
int max(int x,int y)
{
return x>y?x:y;
}
int main()
{
while(scanf("%s",s)!=EOF)
{
int n=strlen(s);
int i,j;
int res=1;
for(i=0;i<n-1;i++)
{
if(s[i]==s[i+1])//如果是偶数长度的回文子串
{
int d=2;
int l=i,r=i+1;
while(l-1>=0&&r+1<n&&s[--l]==s[++r])//向外扩散,不建议用后自增
{
d+=2;
}
res=max(res,d);
}
if(i-1>=0&&i+1<n&&s[i-1]==s[i+1])//奇数长度回文子串
{
int d=3;
int l=i-1,r=i+1;
while(l-1>=0&&r+1<n&&s[--l]==s[++r])//向外扩散
{
d+=2;
}
res=max(res,d);
}
}
printf("%d\n",res);
}
}
1010
?关键信息: TRUE的个数
做法猜测:
a 概率从大到小排序
b 选出前L个为TRUE的概率相加
c R-L个有可能为TRUE的,故选择TRUE和FALSE中较大的一个概率相加,直到 已经选了R个正确的,进入d
d 由于对的已经被选完了,剩下全是错的,加上其错误的概率即可
运行后果然一致。(虽然此题在我看来就是很奇怪)
附上代码
#include<stdio.h>
#include<algorithm>
#include<functional>
using namespace std;
int main()
{
int t;
int L,R,n;
double x[300];
int i,j;
scanf("%d",&t);
for(j=1;j<=t;j++)
{
scanf("%d %d %d",&L,&R,&n);
for(i=0;i<n;i++)
scanf("%lf",&x[i]);
sort(x,x+n,greater<double>());
//此乃大到小快排
//反正冒泡也行
double res=0;
for(i=0;i<n;i++)
{
if(L)
{
res+=x[i];
R--;
L--;
}
else
{
if(x[i]>0.5&&R)
{
res+=x[i];
R--;
}
else res+=1-x[i];
}
}
printf("Data Set %d:\n",j);
printf("%.2f\n",res);
}
}
1011
?难是不难,说不难的话有点难
直接上代码c
#include<stdio.h>
#include<string.h>
char num[10][10]={"zero","one","two","three","four","five","six","seven","eight","nine"};
char cmpy[3];
char a[3][10];
char cmp[3];
char s;
void putcmp(double x,double y)//存入正确的比较符号
{
if(x>y)cmp[0]='>';
else if(x<y)cmp[0]='<';
else cmp[0]='=';
}
void yunsuan()//运算
{
double b,c,d;
for(int i=0;i<10;i++)
{
if(strcmp(num[i],a[0])==0)b=i;
if(strcmp(num[i],a[1])==0)c=i;
if(strcmp(num[i],a[2])==0)d=i;
}
if(s=='+')
b+=c;
else if(s=='-')
b-=c;
else if(s=='*')
b*=c;
else
b/=c;
putcmp(b,d);
}
int main()
{
char d[100];
while(gets(d))
{
memset(a,0,sizeof(a));
memset(cmpy,0,sizeof(cmpy));
int i,k=0,j=0;
bool f=1;
int l=strlen(d);
for(i=0;i<l;i++)
{
//存入第一个数
if(d[i]=='+'||d[i]=='-'||d[i]=='*'||d[i]=='/')
{
f=2;
s=d[i];//存下运算符
a[k][j]=='\0';
k++;j=0;
}
//存第二第三个数以及比较符号
else if(d[i]=='='||d[i]=='<'||d[i]=='>')
{
a[k][j]=='\0';
k++;j=0;
if(d[i]=='=')
{
cmpy[0]='=';
cmpy[1]='\0';
}
//注意判断比较符号是否有两位
else if(d[i]=='<'||'>')
{
cmpy[0]=d[i];
cmpy[1]='\0';
if(d[i+1]=='=')
{
cmpy[1]=d[i+1];
cmpy[2]='\0';
i++;
}
}
}
else a[k][j++]=d[i];
}
a[k][j]='\0';//最后一位加'\0'
//判断除0
if(strcmp(a[1],"zero")==0&&s=='/')
{
printf("expression false\n");
continue;
}
//调用函数运算,存入正确的比较符号到cmp
yunsuan();
//判断比较符号是否正确
if(strcmp(cmpy,cmp)==0)printf("true\n");
else
printf("%s%c%s %s %s\n",a[0],s,a[1],cmp,a[2]);
}
}
1012
关键信息:递归?
什么递归我们不熟,我和打表才是好兄弟?
递归太慢,打表才是真理
附上代码c
#include<stdio.h>
int main()
{
int a,b,c;
int w[30][30][30]={1};
int i,j,k;
for(i=0;i<=20;i++)
for(j=0;j<=20;j++)
{
w[i][j][0]=1;
w[0][i][j]=1;
w[i][0][j]=1;
}
//进行一个表的打
for(i=1;i<=20;i++)
for(j=1;j<=20;j++)
for(k=1;k<=20;k++)
{
if(i<j&&j<k)
{
w[i][j][k]=w[i][j][k-1]+w[i][j-1][k-1]-w[i][j-1][k];
}
else
{
w[i][j][k]=w[i-1][j][k]+w[i-1][j-1][k]+w[i-1][j][k-1]-w[i-1][j-1][k-1];
}
}
while(scanf("%d%d%d",&a,&b,&c),!(a==-1&&b==-1&&c==-1))
{
if(a>20||b>20||c>20)
{
printf("w(%d, %d, %d) = %d\n",a,b,c,w[20][20][20]);
}
else if(a<=0||b<=0||c<=0)
{
printf("w(%d, %d, %d) = %d\n",a,b,c,w[0][0][0]);
}
else printf("w(%d, %d, %d) = %d\n",a,b,c,w[a][b][c]);
}
}
1013
?什么? 并查集 什么?强联通
nonono 我选择找规律
左边出现的值,在右边也必定出现,并且左右值的 个数 都要等于n
附上代码c
#include<stdio.h>
#include<string.h>
int n,m;
int l[10010];
int r[10010];
int main()
{
while(scanf("%d %d",&n,&m),n||m)
{
memset(l,0,sizeof(l));
memset(r,0,sizeof(r));
while(m--)
{
int a,b;
scanf("%d%d",&a,&b);
if(a!=b)
{
l[a]++;//记录左边出现的值
r[b]++;//记录右边出现的值
}
}
int i;
for(i=1;i<=n;i++)
{
if(r[i]==0||l[i]==0)break;
}
if(i==n+1)printf("Yes\n");
else printf("No\n");
}
}
1014
?关键信息:水平竖直一步为1,斜走为sqrt(2)
找规律尔,看不出来就画图
a 判断n m是否为1
b 判断n*m的是奇是偶
附上代码c
#include<stdio.h>
#include<math.h>
int main()
{
int n,m;
scanf("%d%d",&n,&m);
if(n==1||m==1)printf("%.2f\n",(double)n*m*2-2);
else if(n*m%2==0)
printf("%.2f\n",(double)n*m);
else
printf("%.2f\n",(double)n*m-1+sqrt(2));
}
1015
关键信息:拓扑排序+优先队列
此处主要讲述为什么要根据 出度为0 倒着排序,若要学习拓扑排序 私下问我 或者 自行解决 。
如若根据 入度为0 正着排序
例如 5个数,4个要求
5 4
5 1
4 1
2 3
一开始入度为0的有 2 和 5 ,先存入 2 和 5 ,可以发现已经出错了,根据题意,应该是1在2前,而2已经被排到了第一位,故此法不可取。
而倒着排序则不会有此问题。
#include<vector>
#include<iostream>
#include<string>
#include<queue>
#include<string.h>
using namespace std;
#include<stdio.h>
#include<string.h>
vector<int> q[30010];//理解为动态二维数组即可
int in[30010],out[30010];//入度 出度
int topp[30010];
priority_queue<int> que;//优先队列,队头为大
void top(int n)
{
int i,j;
for(i=1;i<=n;i++)//存入出度为0的数
{
if(out[i]==0)
{
que.push(i);
}
}
while(!que.empty())//队列不空
{
int p=que.top();
topp[n--]=p;//倒着存入输出的数组
que.pop();
for(i=0;i<in[p];i++)
{
out[q[p][i]]--;
if(out[q[p][i]]==0)//如果出现新的出度为0的数
{
que.push(q[p][i]);
}
}
}
}
void get()//读取函数
{
int a,b;
scanf("%d%d",&a,&b);
q[b].push_back(a);//记录先于b之前的数存到q[b]
in[b]++;//b的入度
out[a]++;//a的出度
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(q,0,sizeof(q));
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
int n,m;
int i,j;
scanf("%d%d",&n,&m);
int nn=n;
for(i=1;i<=m;i++)
get();
top(n);//拓扑排序函数调用
for(i=1;i<=nn;i++)
{
if(i!=1)printf(" ");
printf("%d",topp[i]);
}
printf("\n");
}
}
|