2025寒假训练第4周

总体情况

这周由于左手被摔骨折了导致没怎么写代码,休息了大概十天

知识点模块

1.当计算多个分数的相加的时候,一般来说采取的思路会有两种
a.找出这些所有数的最小公倍数(称lcm),然后分子乘(lcm/分母),但是这样可能会有爆精度的问题,通分的时候可能longlong也会超过数据范围。

b.所以更好的方法应该是,逐个通分相加然后约分。
实现通分和约分的操作

点击查看代码
int fz=0,fm=1;
    for(int i=0;i<n;i++)
    {
    	//通分相加 
    	int a,b;
    	cin>>a>>b;
    	fz*=b;
    	fz+=a*fm;
    	fm*=b;
    	//约分 
    	int k=gcd(fz,fm);
    	fz/=k,fm/=k;
    	
	}

2.C++的补0
cout<<setw(n)<<setfill('0')<<x; //n为位数
3.从字符串获取字符排版,可以观察一下获取规律,每行每列的字符是怎么来的,然后再进行处理。
4.在map<int,int>mp,中也可以直接用找最大值的方法来寻找最大键,如果最大值更新,ans也更新为键即可
5.在求能否被1111111......整除的时候,可以采取每次增加一位的策略,具体就是先整除得出商,然后看取余是否为0,不为0,乘10再+1,知道取余为0即可
6.利用正则表达式将若干个空格变为一个空格
s=regex_replace(s,regex(R"(\s+)")," ");
7.利用正则表达式实现语句的转化
s=regex_replace(s,regex(R"(\bcan you\b)"),"I can");
8.利用正则表达式,删除句首和句尾的空格,和标点符合前多余的空格
s=regex_replace(s,regex(R"(^\s+|\s+$|\s+=(?=\W))"),"");
9.利用正则表达式实现符合的转化
s=regex_replace(s,regex(R"(\?)"),"!");

题解模块

L1-009 N个数求和
这一题的测试点3,应该是卡以算出所有数的最小公倍数然后再算分子总和在处理这个思路,这个思路可能会导致精度爆了,所以要拿20分应该采用两个两个数通分然后算完约分,再继续算的思路

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long 
#define x first
#define y second
typedef pair<int,int> pii;
#define all(v) v.begin(),v.end()
signed main()
{
	int n;
	cin>>n;
	int  fz=0,fm=1;
    //如果使用最小公倍数去算然后加起来算分母可能会爆精度
    //所以采取边加边约分的方法
	for(int i=0;i<n;i++)
	{
		char s;
		int a,b;
		cin>>a>>s>>b;
		//通分 
		fz*=b;
		fz+=a*fm;
		fm*=b;
		//约分 
		int k=gcd(fz,fm);
		fz/=k;
		fm/=k;
	}
    //输出的时候 讨论只输出分数部分时候当fz%fm==0 和 fz<fm
	if(fz%fm==0){
		cout<<fz/fm;
	}else if(fz<fm){
		cout<<fz<<"/"<<fm;
	}
	else{
		cout<<fz/fm<<" "<<fz%fm<<"/"<<fm;
	}
	
}

L1-019 谁先倒
这题看着不难,但是怎样处理可以花更少的时间,是值得考虑的事情
1.我们跳出循环的条件是谁喝的酒超过自己的酒量了,一般我们思维定势会让h1<0||h2<0去跳出循环,但更加简便的其实是,令x为甲喝的酒,y为乙喝的酒,x+1=h1, y+1=h2去跳出循环,分别各自输出,免得变量的穿插复杂

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long 
#define x first
#define y second
typedef pair<int,int> pii;
#define all(v) v.begin(),v.end()


signed main()
{
    int h1,h2,n;
    cin>>h1>>h2>>n;
    int x=0,y=0;
    while(n--)
    {
    int a1,a2,b1,b2;
    cin>>a1>>a2>>b1>>b2;
    int  mark=a1+b1;
  
    if(a2==mark&&b2!=mark)
    {
         x++;
         if(x==h1+1){
         	cout<<"A"<<endl;
         	cout<<y;
         	break;
		 }
    }else if(a2!=mark&&b2==mark){
        y++;
        if(y==h2+1)
        {
        	cout<<"B"<<endl;
        	cout<<x;
        	break;
		}
    }
    
    }
    
    
}

L1-020 帅到没朋友
1.第3,4测试点,注意当这个数不是5位数的时候,要记得补前面的0,被这个卡了半天。
2.测试点2可能卡的是,一个数字自己出现一次,又和别的数字一起出现一次

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long 
#define x first
#define y second
typedef pair<int,int> pii;
#define all(v) v.begin(),v.end()
signed main()
{
    int n;
    map<int,int>mp,cnt;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        int xx;
        cin>>xx;
        for(int j=0;j<xx;j++)
        {
            int yy;
            cin>>yy; 
		if(xx!=1)	mp[yy]+=xx;//算一下这个人有几个朋友 
        }
    }
    //按顺序把只有自己的和没朋友的存进数组里方便按顺序输出 
    vector<int>v;
    int m; cin>>m;
    for(int i=0;i<m;i++)
    {
        int xx;
        cin>>xx;
        if(mp[xx]==1||mp[xx]==0){
        if(cnt[xx]==0)	v.push_back(xx);
        cnt[xx]++;
		}
    }
    //记得补前导0和注意空格 
    if(v.size()==0) cout<<"No one is handsome";
    else{
        for(int i=0;i<v.size()-1;i++)
        {
            cout<<setw(5)<<setfill('0')<<v[i]<<" ";
        }
        cout<<setw(5)<<setfill('0')<<v[v.size()-1];
        
    }
    
}

L1-023 输出GPLT

1.开四个变量记录,然后每次按gplt去输出,依次减一即可
2.注意大小写都要计数
3.学一下这个思路,这也是一种类型题

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long 
#define x first
#define y second
typedef pair<int,int> pii;
#define all(v) v.begin(),v.end()
signed main()
{
    string s;
    cin>>s;
    int g=0,p=0,l=0,t=0;
    for(int i=0;i<s.size();i++)
    {
        if(s[i]=='G'||s[i]=='g') g++;
        if(s[i]=='P'||s[i]=='p') p++;
        if(s[i]=='L'||s[i]=='l') l++;
        if(s[i]=='T'||s[i]=='t') t++;
    }
   	 while(g>0||p>0||l>0||t>0){
   		if(g>0) cout<<"G",g--;
   		if(p>0) cout<<"P",p--;
   		if(l>0) cout<<"L",l--;
   		if(t>0) cout<<"T",t--;
	}
    
}

L1-025 正整数A+B

1.注意b要用getline来,且用cin.ignore()来吃掉前面的空格
2.先检查字符串是否只有数字,然后检查数字是否符合范围,然后用stoi函数转为int类即可

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long 
#define x first
#define y second
typedef pair<int,int> pii;
#define all(v) v.begin(),v.end()
signed main()
{
	string a,b;
    cin>>a;
 	cin.ignore();
    getline(cin,b);
 
    
  	for(int i=0;i<a.size();i++)
  	{
  		if(a[i]<'0'||a[i]>'9'){
  			a="?";
  			break;
		}
	}
	
	for(int i=0;i<b.size();i++)
  	{
  		if(b[i]<'0'||b[i]>'9'){
  			b="?";
  			break;
		}
	}
	
    if(a!="?")
	{
		int k=stoi(a);
		if(k>1000||k<1) a="?";
	 } 
	 
	 if(b!="?")
	{
		int k=stoi(b);
		if(k>1000||k<1) b="?";
	 } 

 	if(a!="?"&&b!="?")	
 	{
 	cout<<a<<" + "<<b<<" = "<< stoi(a)+stoi(b);
	}
 else cout<<a<<" + "<<b<<" = "<<"?";
    
    
}

L1-027 出租
1.把数字按顺序遍历push_back到v里面,标记一下避免重复,然后排序一下,然后查找一下字符串每个字符在v里面对应的下标即可
2.输出格式注意一下,先输出首个数,在输出,和数

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long 
#define x first
#define y second
typedef pair<int,int> pii;
#define all(v) v.begin(),v.end()
signed main()
{
    string s;
    cin>>s;
    cout<<"int[] arr = new int[]{";
    map<int,int>mp;
    vector<int>v;
    for(auto t:s)
    {
        if(mp[t-'0']==0) 
        {
            v.push_back(t-'0');
            mp[t-'0']++;
        }
    }
    sort(all(v),greater<int>());
    cout<<v[0];
    for(int i=1;i<v.size();i++) cout<<","<<v[i];
    cout<<"};"<<endl<<"int[] index = new int[]{";
    auto  k=find(all(v),s[0]-'0');
    cout<<distance(v.begin(),k);
    
    for(int i=1;i<s.size();i++)
    {
        for(int j=0;j<v.size();j++)
        {
            if(s[i]-'0'==v[j]) cout<<","<<j;
        }
    }
    cout<<"};";
    
    
}

L1-030 一帮一
1.这题看着简单,但是我五分钟么有写出来,就相当于不会写
2.找01配对,可以直接等价于找两个不同的数,所以只需要两层循环,然后标记一下被遍历过的就可以,我竟然纠结了这么久

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long 
#define x first
#define y second
typedef pair<int,int> pii;
#define all(v) v.begin(),v.end()
signed main()
{
	int n;
	cin>>n;
	string s[55];
	map<int,int>mp;
	int id[55];
	for(int i=1;i<=n;i++)
	{
		string sb;
		int x;
		cin>>x>>sb;
		s[i]=sb;
		id[i]=x;
	}

	for(int i=1;i<=n/2;i++)
	{
		cout<<s[i]<<" ";
		for(int j=n;j>n/2;j--)
		{
			if(mp[j]==0&&id[i]!=id[j])
			{
				mp[j]=1;
				cout<<s[j];
				break;
			}
		}
		cout<<endl;
	}
	
}

L1-033 出生年
1.这题麻烦在就是不足四位数的该怎么处理,其实不足四位数的年份相当于提供了一个0,这个数字,只要这个数小于1000,我们把0放进set即可
2.解决了1以后,只要枚举每个数,然后把每个数字放进set,看set的size是否等于n即可,然后结果补0输出一下即可

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long 
#define x first
#define y second
typedef pair<int,int> pii;
#define all(v) v.begin(),v.end()
int dx[]={0,1,-1,0};
int dy[]={-1,0,0,1};


signed main()
{
	
	int y,n;
	cin>>y>>n;
	set<int>se;
	int cnt=0;
	for(int i=y;i<=5000;i++)
	{
		int x=i;
		if(i<1000) se.insert(0);
		while(x>0)
		{
			se.insert(x%10);
			x/=10;
		}
		if(se.size()==n){ 
			cout<<cnt<<" ";
			if(i<10) cout<<"000"<<i;
			else if(i<100) cout<<"00"<<i;
			else if(i<1000) cout<<"0"<<i;
			else cout<<i;
 			break;
		}
		se.clear();
		cnt++;
	}
	
	
}

L1-039 古风排版
1.行数代表每行获取字母的起点索引值,比如第一行就是T,就是第一个字符,然后该行对应的字符就是行数+=n,循环遍历一下,获取每行的字符串,然后倒置一下,再输出即可,不理解参考我的代码和样例即可理解,就是用一下每行字符的规律

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long 
#define x first
#define y second
typedef pair<int,int> pii;
#define all(v) v.begin(),v.end()
int dx[]={0,1,-1,0};
int dy[]={-1,0,0,1};


signed main()
{
	int n;cin>>n;//n是行数 
	string s; getline(cin,s);
	getline(cin,s);
	int maxx=0;
	for(int i=1;i<=n;i++)
	{
		string sb;
		int cnt=0;//每行最多有几个用来处理最后一行 
		for(int j=i;j<=s.size();j+=n)
		{
			sb+=s[j-1];
			cnt++;
		}
		maxx=max(cnt,maxx);
		if(cnt<maxx) for(int i=0;i<maxx-cnt;i++) sb+=' ';
		reverse(all(sb));
		cout<<sb<<endl;
	}
	
}

L1-043 阅览室
1.这题天数就是大循环,然后在大循环里用while写小循环,在借的时候标记一下,然后遇到E以后检查一下是否这个被标记过,然后进行计算就行了
2.时间处理直接转化为分钟,然后遇到E后加到sum里,记得加完一次后记得把这个标记重新恢复为0,不然会出现统计了还了多次的情况

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long 
#define x first
#define y second
typedef pair<int,int> pii;
#define all(v) v.begin(),v.end()
int dx[]={0,1,-1,0};
int dy[]={-1,0,0,1};


signed main()
{
	int n; cin>>n;
	int hh,mm,id;
	char cc,cm;
	map<int,int>st,mp;//st用来标记,mp存时间 
	for(int i=0;i<n;i++)
	{
		int sum=0,cnt=0;
		cin>>id>>cc>>hh>>cm>>mm;
		while(id!=0)
		{
			if(cc=='S'){
			st[id]=1;
			mp[id]=hh*60+mm;
			}
			if(cc=='E'&&st[id]==1){
				sum+=hh*60+mm-mp[id];
				cnt++;
				st[id]=0;//注意记得这一步别忘了
                //不然会出现统计了多次还书的时间
			}
			cin>>id>>cc>>hh>>cm>>mm;
		}
		
		if(cnt==0) cout<<0<<" "<<0;
		else cout<<cnt<<" "<<fixed<<setprecision(0)<<1.0*sum/cnt;
		cout<<endl;
	}
}

L1-046 整除光棍

1.我们采取增加1的位数,然后每次整除输出商,然后取余看是否为0的策略,不为0,增加1的位数,直到最后得到取余为0

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long 
#define x first
#define y second
typedef pair<int,int> pii;
#define all(v) v.begin(),v.end()
int dx[]={0,1,-1,0};
int dy[]={-1,0,0,1};


signed main()
{
	int n,x=1,w=1;
	cin>>n;
	while(x<n)
	{
		x*=10;
		x++;
		w++;
	}
	
	while(1)
	{
		cout<<x/n;
		x%=n;
		if(x%n==0) break;
		x*=10;
		x++;
		w++;
	}
	cout<<" "<<w;
}

L1-049 天梯赛座位分配

1.这题按照1 2 3 4 5 6 7 8 9 10.....把每个数填到相应的数组里面,就是1放到1(二维数组的第一维),2放到2,3放到3,4放到1,5放到2,6放到3,这样类推填下去。然后检查一下是否剩一个队伍,最后一个队伍加等于2即可

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long 
#define x first
#define y second
typedef pair<int,int> pii;
#define all(v) v.begin(),v.end()
int dx[]={0,1,-1,0};
int dy[]={-1,0,0,1};
int f[105];//用来检查是否已经填完了 
signed main()
{
	int n,len=0,tt=0,sum=0;//len为每队的当前人数 
	cin>>n;
	vector<int>a[105];
	int m[105]={0};
	for(int i=1;i<=n;i++)
	{
		int x;cin>>x;
		m[i]=x*10;
		sum+=m[i];
	}

	for(int i=1; ; )
	{
        //每n次的放数 循环下去直到放满
		int t=1;
		while(t<=n)
		{
			if(a[t].size()<m[t])
			{
				tt++;
				a[t].push_back(i);
				if(len+1==n) i+=2;
				else i+=1;
			}
			
			if(a[t].size()>=m[t]&&f[t]==0)
			{
				f[t]=1;
				len++;
			}
			t++;
		}
		
		if(tt==sum) break;
	}
	
	for(int i=1;i<=n;i++)
	{
		cout<<"#"<<i<<endl;
		for(int j=0;j<a[i].size();j++)
		{
			if(j%10!=0) cout<<" ";
			cout<<a[i][j];
			if(j%10==9) cout<<endl;
		}
		//cout<<endl;
	}
}

L1-050 倒数第N个字符串
1.相当于26进制,因为每个位置上都可以选择26个字母中的任何一个,那么我们将pow(26,l)-n,得到要求的数是第几位数,然后转化为26进制上的每一位即可
2.当然注意位数不够时要补a,第二个和第四个测试点就是卡这个

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long 
#define x first
#define y second
typedef pair<int,int> pii;
#define all(v) v.begin(),v.end()
int dx[]={0,1,-1,0};
int dy[]={-1,0,0,1};
int f[105];//用来检查是否已经填完了 
signed main()
{
	int l,n;
	cin>>l>>n;
	int t=pow(26,l)-n;
	string s;
	for(int i=1;i<=l;i++) //这样写就会自动在位数不足的时候把0填进去
        //相当于自动补了a
	{
		s+=t%26+'a';
		t/=26;
	}
	reverse(all(s));
	cout<<s;
}

L1-058 6翻了
1.这题虽然很简单,但是可能处理的不好会下标越界了,用一种不会越界的方法
2.遇到6就计数,然后遇到下一个不是6的看cnt是多少输出相应的变形即可,然后不是6的直接输出

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long 
#define x first
#define y second
typedef pair<int,int> pii;
#define all(v) v.begin(),v.end()
int dx[]={0,1,-1,0};
int dy[]={-1,0,0,1};

signed main()
{
   string s;
    getline(cin,s);
    int cnt=0;
    for(int i=0;i<=s.size();i++)//最后一个记得是等号 
    {
        if(s[i]=='6') cnt++;
        else {
        	if(cnt>9) cout<<"27";
        	else if(cnt>3) cout<<"9";
        	else {
        		for(int i=0;i<cnt;i++) cout<<'6';
			}
        	cnt=0;
        	cout<<s[i];
		}
    }
}

L1-059 敲笨钟
1.利用,和.这两个特殊的位置,检查前面三个字符是否都为ong
2.找到.的前面第三个空格的位置,记录一下这个位置,直接输出到这里,然后后面接dabenzhong

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long 
#define x first
#define y second
typedef pair<int,int> pii;
#define all(v) v.begin(),v.end()
int dx[]={0,1,-1,0};
int dy[]={-1,0,0,1};
bool check(int i,string s)
{
	if(s[i-1]=='g'&&s[i-2]=='n'&&s[i-3]=='o') return 1;
	else return 0;
}
signed main()
{
  	int n;
  	cin>>n;
	cin.ignore();
  	for(int i=1;i<=n;i++)
  	{
  		string s;
  		getline(cin,s);
  		int cnt=0,p; 
  		//找出句号前第三个空格 
  		for(int j=s.size()-1;j>=0;j--)
  		{
  			if(s[j]==' ') cnt++;
  			if(cnt==3){
  				p=j;
  				break;
			  }
		}
	
  		bool f1,f2;
  		for(int j=0;j<s.size();j++)
  		{
  			if(s[j]==',') f1=check(j,s);
			if(s[j]=='.') f2=check(j,s);
		}
		if(f1&&f2){
			for(int i=0;i<=p;i++) cout<<s[i];
			cout<<"qiao ben zhong.";
		}
		else cout<<"Skipped";
		cout<<endl;
	}
}

L1-064 估值一亿的AI核心代码
1.用正则表达式来处理,注意一个坑点,I可能被多次转化,比如can you 转化出了I ,I又会被转化,所以将I标记成其他字符

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long 
#define x first
#define y second
typedef pair<int,int> pii;
#define all(v) v.begin(),v.end()
int dx[]={0,1,-1,0};
int dy[]={-1,0,0,1};
string s;
signed main()
{
    int n;
    cin>>n;
    cin.ignore();
    while(getline(cin,s))
    {
    	cout<<s<<endl<<"AI: ";
    	s=regex_replace(s,regex(R"(\s+)")," ");
    	// \s+表示多个空格,把若干个空格转化为一个空格 
		s=regex_replace(s,regex(R"(^\s+|\s+$|\s+(?=\W))"),"");
		//把句子开头结尾的空格,以及标点符合前的空格全部消除
		// ^代表开头  $代表结尾 \W是非数字,字母的字符 
		s=regex_replace(s,regex(R"(\bI\b)"),"mark_mark");
		//I暂时转化为mark 防止后面can you 出现的I又被转化
		// \b匹配单词的边界 
		for(int i=0;i<s.size();i++) if(s[i]!='I') s[i]=tolower(s[i]);
    	s=regex_replace(s,regex(R"(\bcan you\b)"),"I can");
    	s=regex_replace(s,regex(R"(\bcould you\b)"),"I could");
    	//把can you 和 could you 转化为 I can I could 
    	s=regex_replace(s,regex(R"(mark_mark|\bme\b)"),"you");
    	s=regex_replace(s,regex(R"(\?)"),"!");
    	//把?转化为! 
    	cout<<s<<endl;
	}
}

参考了https://www.liuchuo.net/archives/8741

posted on 2025-02-23 17:52  swj2529411658  阅读(43)  评论(0)    收藏  举报

导航