2. ECNU水题-2
1.找数
//超时我的程序,给我思路,一般大于int的数不要设计计算,否则很慢
#include<bits/stdc++.h>
using namespace std;
bool isUpNum(long long num) {
stack<int> s;
while(num>0){
int n;
n=num%10;
num/=10;
if(s.empty()){
s.push(n);
}else if(s.top()>n){
return false;
}else if(s.top()<=n){
s.push(n);
}
}
if(num==0){
return true;
}
}
int main(){
int T;
cin>>T;
int j=T;
long long num;
while(T--){
cin>>num;
while(!isUpNum(num)){
num++;
}
cout<<"case #"<<j-T-1<<":"<<endl;
cout<<num<<endl;
}
}
//别人思路及代码 https://blog.csdn.net/lecholin/article/details/77916349
最自然的想法是,通过扫描s[i] < s[i+1]找到上升点,然后对上升点前的s[i-1]+1,后面全部填0。但是要考虑到s[i-1]+1后可能会破坏前面的非上升序列,因此还要将前面的元素考虑进来。
采取的办法是,在扫描上升点的同时,维护经过的最小数字及位置,找到上升点后,判断s[i-1]+1和该最小数字的大小,如果s[i-1]+1更小,那就在后面填0即可,否则要对最小数字+1,并在其后全填0。(实质是让填0前的那个数字保持最小)
例子:7400920的上升点在第二个0和9之间,如果变成7101000不满足“非上升”,但是变成7410000则满足。
#include <iostream>
using namespace std;
int main()
{
int kase;
cin >> kase;
string s;
for(int t = 0; t < kase; ++t)
{
cin >> s;
int min_num = 10, min_pos = 0; //最小数字及所在小标
for (int i = 0; i < s.size()-1; ++i)
{
if (s[i] < s[i+1]) //出现上升
{
int tmp = s[i] - '0' + 1, pos = (tmp>min_num)?min_pos:i; //pos为更新的位置
//要更新的数字加1,后面全填0
s[pos]++;
for(int j = pos + 1; j < s.size(); ++j)
s[j] = '0';
break;
}
else if (s[i]-'0' < min_num) //维护经过的最小数字
{
min_num = s[i] - '0';
min_pos = i;
}
}
cout << "case #" << t << ':' << endl;
cout << s << endl;
}
return 0;
}
2.四位数加法
#include<bits/stdc++.h>
using namespace std;
//求分子分母最大公倍数
long long getMaxCommonMultiple(long long mother,long long son){
long long min ;
if(mother>son){
min=son;
}else if(mother<son){
min=mother;
}else{
return son;
}
//缺考虑了
if(son%mother==0){
return mother;
}
long long i;
for(i=(long long)sqrt(min);i>0;i--){
if(mother%i==0&&son%i==0){
return i;
}
}
//如果i==1说明没有公倍数,提示函数调用者即可
if(i==1){
return 1;
}
}
long long FractionSum(int aaaabbbb, int ccccdddd) {
int a,b,c,d;
long long son,mother;
a=aaaabbbb/10000;
b=aaaabbbb%10000;
c=ccccdddd/10000;
d=ccccdddd%10000;
mother=b*d;
son=a*d+c*b;
long long i=getMaxCommonMultiple(mother,son);
if(i==1){
return son*100000000+mother;
}else{
son/=i;
mother/=i;
return son*100000000+mother;
}
}
int main(){
int a, b, c, d;
long long r;
scanf("%d%d%d%d", &a, &b, &c, &d);
r = FractionSum(a * 10000 + b, c * 10000 + d);
printf("%d/%d+%d/%d=%lld/%lld.\n", a, b, c, d,
r / 100000000, r % 100000000);
return 0;
}
3.进制转换
//1.初始思路,超时。。。。
#include<bits/stdc++.h>
using namespace std;
bool isTrue(long long num,int ary,int m){
int arr[200];
int i=0,cnt=0;
do{
arr[i]=num%ary;
num/=ary;
i++;
}while(num!=0);
for(int j=0;j<i;j++){
if(arr[j]==0){
cnt++;
}else{
break;
}
}
if(cnt==m){
return true;
}else{
return false;
}
}
int main(){
long long l,r;
int k,m,T;
cin>>T;
while(T--){
cin>>l>>r>>k>>m;
int cnt=0;
for(;l<r;l++){
if(isTrue(l,k,m)){
cnt++;
}
}
cout<<cnt<<endl;
}
}
//2.更新、中途break 也超时。。。
#include<bits/stdc++.h>
using namespace std;
bool isTrue(long long num,int ary,int m){
for(int i=0;i<m;i++){
if(num%ary==0&&num>0){
num/=ary;
}else{
return false;
}
}
if(num%ary!=0){
return true;
}
}
int main(){
long long l,r;
int k,m,T;
cin>>T;
while(T--){
cin>>l>>r>>k>>m;
int cnt=0;
for(;l<r;l++){
if(isTrue(l,k,m)){
cnt++;
}
}
cout<<cnt<<endl;
}
}
//大佬思路
题目要求的时在区间范围内的m进制后有k个零的数有多少,很容易想到如果一个数的m进制后有k个零,就一定能被m^k整除,而在含k个零中,一定存在含k+1个零的(含k+1个零就意味着一定含k个零),在1,2,3....x中,能被m^k整除的有⌊x/m^k⌋个,所以只含k个零的个数有ansx = ⌊x/m^k⌋-⌊x/m^k+1⌋,区间的话就是ansr - ansl-1 注意是l-1
但是有个问题,就是直接计算mk 会溢出的问题,而且又不能取模,根据式子,就要用到除法,如果溢出了,相除肯定变成了0(据说long double好像也行,我没试过)
#include<bits/stdc++.h>
using namespace std;
int main(){
long long l,r;
int k,m,T;
cin>>T;
while(T--){
cin>>l>>r>>k>>m;
l--;//这步为什么
long long rf=r,lf=l;
for(int i=0;i<m;i++){
rf=(long long)(rf/k);
lf=(long long)(lf/k);
}
long long rfs=(long long)(rf/k);
long long lfs=(long long)(lf/k);
cout<<rf-lf-rfs+lfs<<endl;
}
}
4.斐波那契求和
#include<bits/stdc++.h>
using namespace std;
struct Fraction{
unsigned long long up,down;
};
long long gcd(long long a,long long b){
if(b==0) return a;
else return gcd(b,a%b);
}
Fraction reduce(Fraction c){
//求出两个数最大公约数
long long maxC = gcd(c.down,c.up);
c.down/=maxC;
c.up/=maxC;
return c;
}
//分数加法
Fraction add(Fraction a,Fraction b){
Fraction c;
c.down=a.down*b.down;
c.up=a.up*b.down+b.up*a.down;
return reduce(c);//约分
}
int main(){
int T;
cin>>T;
while(T--){
int N;
cin>>N;
// N=N+1;//不知道为什么。。。整体少加了一位
unsigned long long f[N+2];
f[1]=1,f[2]=1;
for(int i=3;i<=N+2;i++){
f[i]=f[i-1]+f[i-2];
}
Fraction fraction[N+1];//用来存分数
// cout<<f[3]<<f[1]+f[2]<<endl;
// f[3]%=10;//在N未加1时,为什么这里的f[3]是52...
// cout<<f[3]<<f[1]+f[2]<<endl;
for(int i=1;i<=N;i++){
fraction[i].up=f[i+2];
fraction[i].down=f[i+1];
}
Fraction result;
result=fraction[1];
// cout<<result.up<<"/"<<result.down;
for(int i=2;i<=N;i++){
result=add(result,fraction[i]);
}
cout<<result.up<<"/"<<result.down;
}
}
5.统计单词个数
#include<bits/stdc++.h>
using namespace std;
int main(){
set<string> s;
s.insert("for");
s.insert("of");
s.insert("a");
s.insert("an");
s.insert("the");
s.insert("and");
int T;
string line;
int cur=0;
cin>>T;
cin.get();//取得第一个回车符
while(T--){
int cnt=0;
set<string> set;
set=s;
getline(cin,line);//取得未知个数字符串
for (auto &i : line){//把单个字符都转变为小写
i = tolower(i);
}
string temp;
istringstream iss(line);
while(iss>>temp){//取得以空格为分隔符的字符串
set.insert(temp);
if(set.size()==7){
set.erase(temp);
cnt++;
}
}
cout << "case #" << cur++ << ":\n" <<cnt<< '\n';
}
}
6.爬阶梯问题
- 题目地址(https://acm.ecnu.edu.cn/problem/3051/)
#include<bits/stdc++.h>
using namespace std;
//这种题目从结果反推原因,比如说你在第五号台阶,那你前面一步可能情况时在第一、第二、第三、第四个台阶,就把这些可能相加即可。
int main(){
unsigned long long a[51];
a[1]=1;
a[2]=2;
a[3]=4;
a[4]=8;
for(int i=5;i<=50;i++){
a[i]=a[i-1]+a[i-2]+a[i-3]+a[i-4];
}
int T;
cin>>T;
int cur=T;
while(T--){
cout<<"case #"<<cur-T-1<<":"<<endl;
int n;
cin>>n;
cout<<a[n]<<endl;
}
}
7.找数字
//运行错误,利用桶排序,但是测试数据有负数加正整数
#include<bits/stdc++.h>
using namespace std;
int main(){
int N;
while(cin>>N){
int cur=N;
int n;
// int a[N];
int b[N];
for(int j=0;j<N;j++){
b[j]=0;
}
// memset(a,0,cur);
// cout<<(1<<31)-1<<endl;
int min=(1<<31)-1;
int k=0;
while(N--){
scanf("%d",&n);
if(min>n){
min=n;
}
b[k++]=n;
}
min=abs(min);
int a[min+cur];
for(int j=0;j<cur+min;j++){
a[j]=0;
}
for(int j=0;j<cur;j++){
a[b[j]+min]++;
}
for(int i=0;i<cur;i++){
if(a[i]>cur/2){
cout<<i-min<<endl;
}
}
}
}
//大佬思路
#include<bits/stdc++.h>
using namespace std;
int main(){
int N,temp;
while(cin>>N){
int res=0;
int cnt=0;
for(int i=0;i<N;i++){
scanf("%d",&temp);
if(cnt==0){
res=temp;//res上面一个数据,temp当前数据
cnt++;
}else if(temp==res){
cnt++;
}else {
cnt--;
}
}
cout<<res<<endl;
}
}
8.数据压缩
#include<bits/stdc++.h>
using namespace std;
//发现题目在调试后才能ac,rubbish
int main(){
int N;
while(cin>>N){
getchar();
int n=0;
while(N--){
string str;
getline(cin,str);
cout<<"case #"<<n++<<":"<<endl;
int cur=1;
char c;
for(int i=0;i<str.length();i++){//这里刚好在i+1==str.length(),a[i+1]=='\0';没报异常,如果声明数组则会溢出
c=str[i];
if(c==str[i+1]){
cur++;
if(cur==255){
cout<<"255"<<c;
cur=0;
}
}
if(c!=str[i+1]&&cur!=0){//当输入数据刚好255时,禁止输出
cout<<cur<<c;
cur=1;
}
}
cout<<endl;
}
}
}
9.max max sum
//初始思路,getline()得到的字符串如果有负号就会出现问题
#include<bits/stdc++.h>
using namespace std;
int main(){
string str;
int s[100000];//存各区间和数组
memset(s,0,sizeof(s));
// cout<<s[0]<<endl;
while(getline(cin,str)){
int interval = str[0]-'0';
int nums = str[2]-'0';
int sum=0;
queue<int> q;
//求解第一个interval的sum,并压入队列
for(int i=4;i<2*interval+4;i+=2){
// cout<<i<<" "<<str[i]<<endl;
sum+=(str[i]-'0');
q.push(str[i]-'0');
}
s[0]=sum;
int k=1;
for(int j=2*interval+4;j<str.length();j+=2){
q.push(str[j]-'0');
sum+=(str[j]-'0');
sum-=(q.front());
q.pop();
s[k++]=sum;
}
for(int i=0;i<k;i++){
cout<<s[i]<<" ";
}
cout<<endl;
}
}
//更新二版,提交出错,不知道什么原因。。。测试数据可以,可能数据量大吧
#include<bits/stdc++.h>
using namespace std;
int maxsub(int a[],int length){
int thisSum=0,maxSum=-1001;
for(int i=0;i<length;i++){
thisSum+=a[i];
if(thisSum>maxSum){
maxSum=thisSum;
}
if(thisSum<0){
thisSum=0;
}
}
return maxSum;
}
int main(){
int interval;
int nums;
while(cin>>interval>>nums){
int s[nums];
memset(s,0,sizeof(s));
int i=0;
while(nums--){
scanf("%d",&s[i++]);
}
queue<int> q;
int sums[i];//存储区间和
int sum=0;
for(int i=0;i<interval;i++){
sum+=s[i];
q.push(s[i]);
}
memset(sums,0,sizeof(sums));
sums[0]=sum;
int k=1;
for(int j=interval;j<i;j++){
q.push(s[j]);
sum+=s[j];
sum-=q.front();
q.pop();
sums[k++]=sum;
}
cout<<maxsub(sums,k)<<endl;;
// for(int i=0;i<k;i++){
// cout<<sums[i]<<" ";
// }
// cout<<endl;
}
}
//大佬利用动态规划
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 1e6 + 10;
const int INF = 0x3f3f3f3f;//10亿
int dp[MAXN], a[MAXN], mmax[MAXN];
int main()
{
int n, m, Max;
while(scanf("%d%d", &m, &n) != EOF)
{
memset(dp, 0, sizeof(dp));
memset(mmax, 0, sizeof(mmax));
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
for(int i = 1; i <= m; i++)
{
Max = -INF;
for(int j = i; j <= n; j++)
{
dp[j] = max(dp[j - 1] + a[j], mmax[j - 1] + a[j]);
mmax[j - 1] = Max;
Max = max(Max, dp[j]);
}
}
printf("%d\n", Max);
}
return 0;
}
10.找规律
#include<bits/stdc++.h>
using namespace std;
//被迫用C?
int main(){
int N;
scanf("%d",&N);
while(N--){
int num;
scanf("%d",&num);
if(num==1){
printf("1\n");
continue;
}
num--;
int i=sqrt(num<<1);
if((i*(i+1))>>1==num){//右移动比除法快
printf("1\n");
}else{
printf("0\n");
}
}
}