2021天梯赛补题

题目详情 - L2-039 清点代码库 (pintia.cn)

思路:

  1. 因为map可以存stl容器,我们可以用vector存每一行信息,再用map存储每一行产生的vector,记录其出现次数
  2. map存vector时也会自动按vector大小比较,给每一种输出按小到大排序。
  3. 那么我们最后只需要按map顺序用vector>>ans存储map的每一个vector及其次数即可,然后再排序。
  4. (注意,把出现次数改为负的才可以用less排序,不可以不改就使用greater来排序,会打乱map原本排好的按小到大顺序,否则就自定义排序也可以)
#include 
using namespace std;
#define ll               long long
#define endl             "\n"
const int N = 2e5 + 10;
map,int>mp;
vector>>ans;
void mysolve()
{
	int n,m,x;
	cin>>n>>m;
	for(int i=1; i<=n; ++i)
		{
			vectortmp;
			for(int j=1; j<=m; ++j)cin>>x,tmp.push_back(x);
			mp[tmp]++;
		}
	for(auto &k:mp)ans.push_back({-k.second,k.first});
	sort(ans.begin(),ans.end());
	cout<> t;
	while (t--)
		{
			mysolve();
		}
	system("pause");
	return 0;
}

题目详情 - L3-028 森森旅游 (pintia.cn)

思路:

  1. 我们想到每次只改一个点,那么我们可以记录所有点到起点与终点的距离,然后维护区间最小即可
  2. 所以首先跑两遍堆优化dijksta
  3. 因为只维护区间一个数据,所以可以用multiset存储值,就不需要使用线段树或者树状数组了
#include 
using namespace std;
#define ll               long long
#define endl             "\n"
#define int              long long
typedef pair pii;
const ll llINF = 0x3f3f3f3f3f3f3f3f;//ll型的llINF
const int N =2e5+10;

struct node
{
	int v,c,d;
};
vectoredge1[N],edge2[N];
int b[N];
int n,m,q;

void dijksta(int st,vector&dis,bool fl)//正反dijksta
{
	dis[st]=0;
	priority_queue,greater>q;
	q.push({dis[st],st});
	if(!fl)
		while(!q.empty())
			{
				int u=q.top().second;
				q.pop();
				for(node k:edge1[u])
					{
						if(dis[k.v]>dis[u]+k.c)
							{
								dis[k.v]=dis[u]+k.c;
								q.push({dis[k.v],k.v});
							}
					}
			}
	else
		{
			while(!q.empty())
				{
					int u=q.top().second;
					q.pop();
					for(node k:edge2[u])
						{
							if(dis[k.v]>dis[u]+k.d)
								{
									dis[k.v]=dis[u]+k.d;
									q.push({dis[k.v],k.v});
								}
						}
				}
		}
}
void mysolve()
{
	cin>>n>>m>>q;
	int x,y,c,d;
	vectordis1(n+1,llINF),dis2(n+1,llINF);
	for(int i=1; i<=m; ++i)cin>>x>>y>>c>>d,edge1[x].push_back({y,c,d}),edge2[y].push_back({x,c,d});
	dijksta(1,dis1,0),dijksta(n,dis2,1);
	multisetst;
	for(int i=1; i<=n; ++i)
		{
			cin>>b[i];
			if(dis1[i]!=llINF&&dis2[i]!=llINF)st.insert(dis1[i]+(dis2[i]+b[i]-1)/b[i]);//注意dis为llINF时,是不存在这种走法的,此时强行更新会污染数据,所以必须都可以走才更新
		}
	while(q--)
		{
			cin>>x>>y;
			if(dis1[x]!=llINF&&dis2[x]!=llINF)//注意边要可以走
				{
					st.erase(st.find(dis1[x]+(dis2[x]+b[x]-1)/b[x]));
					b[x]=y;
					st.insert(dis1[x]+(dis2[x]+b[x]-1)/b[x]);
				}
			cout<<*st.begin()<> t;
	while (t--)
		{
			mysolve();
		}
	system("pause");
	return 0;
}

题目详情 - L3-029 还原文件 (pintia.cn)

思路:

  1. 他搞得好像花里胡哨,但是因为M只有100,我不仅可以暴力O(n^2),甚至可以暴力O(n^3)
  2. 所以,我们直接用string存每一行数据,然后dfs匹配即可(必须dfs,因为我可能有多个片段开头一点是相同的,你总不能说他们各自的位置可以随便放吧)
#include 
using namespace std;
#define ll               long long
#define endl             "\n"
#define endll            endl<ans;
bool flag;
int m,k;
void dfs(int num,int p)
{
	if(num==m)//如果能m段匹配完,说明是正确答案,不用再dfs了
		{
			flag=1;
			return;
		}
	if(flag)return;
	for(int j=1; j<=m; ++j)
		{
			if(!vis[j])
				{
					int len=(int)s[j].size();
					if(b.substr(p+1,len)==s[j])
						{
							vis[j]=1;
							int tmp=p;
							ans.push_back(j);

							for(int x=p+len; x>=0; --x)if(b[x]==' ')
									{
										tmp=x;
										break;
									}
							dfs(num+1,tmp);
							if(flag)return;
							ans.pop_back();
							vis[j]=0;
						}
				}
		}
}

void mysolve()
{
	int n;
	cin>>n;
	getchar();
	getline(cin,b);
	b=' '+b;
	int p=0;
	cin>>m;
	for(int i=1; i<=m; ++i)
		{
			cin>>k;
			getchar();
			getline(cin,s[i]);
		}
	dfs(0,p);
	for(int i=0; i<(int)ans.size(); ++i)
		{
			if(i!=0)cout<<" ";
			cout<> t;
	while (t--)
		{
			mysolve();
		}
	system("pause");
	return 0;
}

你可能感兴趣的:(acm训练赛补题,c++,算法,开发语言)