1. vj团队赛3补题(上午

vj题解

https://blog.nowcoder.net/n/33590b62f85540cba97c55026be98480
https://www.cnblogs.com/ch-hui/p/12767416.html

代码板子

#include<bits/stdc++.h>
using namespace std;
#define endl '\n';
#define dbg(x) cout<<#x<<"="<<endl
#define line cout<<endl<<"=========="
#define mark cout<<"***"<<endl;
#define int long long
//#define double long long double
#define ll long long
#define INF -1e18;
#define IOS ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr)
#define pi acos(-1.0)
#define ull unsigned long long
#define pb push_back
#define lowbit(x)&(-x)
#define pii pair<int,int>
int lcm(int a,int b)
{
	return a/__gcd(a,b)*b;
}
const int mod=998244353;
const double eps=1e-6;

}

void solve()
{


}
signed main()
{
	IOS;
	int T;
	T=1;
	cin>>T;
	for(int cases=1; cases<=T; cases++)
	{
		cout<<"Case #"<<cases<<": "<<endl;
		solve();
	}
	return 0;
}

字符串序列变换后能否实现分类(没看懂)

一串牌友rgb三个字母组成,现有两个堆,问能否把他们分类。
https://vjudge.net/contest/642757#status//K/0/
eg rgbrgb rrggbb
//纸牌分类问题
https://www.cnblogs.com/legendmaner/archive/2013/05/06/3062323.html
image

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e7+10;
int n;
char c[6][3]={
    {'R','G','B'},
    {'R','B','G'},
    {'G','R','B'},
    {'G','B','R'},
    {'B','G','R'},
    {'B','R','G'},
};
void solve(){
    string s;
    cin>>s;
    int len=s.length();
    int flag=0;
   for(int i=0;i<6;i++){
        int sum1=0,sum2=0;
        int r=0,l=0;
        // 统计当前模式下的颜色分布情况
        for(int j=0;j<len;j++){
            if(s[j]==c[i][0]){
                sum1++; r=j; // 统计第一个颜色出现的次数,记录最后一个位置
            }
            if(s[j]==c[i][2]) sum2++; // 统计第三个颜色出现的次数
        }
        // 找到第一个出现第三个颜色的位置
        for(int j=0;j<len;j++){
            if(s[j]==c[i][2]){
                l=j; break;
            }
        }
        // 统计从第一个第三个颜色的位置到第一个位置第二个颜色出现的次数
        for(int j=l;j>=0;j--){
            if(s[j]==c[i][1]) sum2++;
        }
        // 统计第一个第一个颜色后的位置到最后颜色出现的次数
        for(int j=r+1;j<len;j++){
            if(s[j]==c[i][1]) sum1++;
        }
        if(sum1+sum2==len){
            flag=1;break;
        }
    } 
    if(flag) cout<<"YES\n";
    else cout<<"NO\n";  
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int t=1;
    // cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

区间问题(反向遍历)(分治)

两种房间,一种需要特定通行证,一种可过但过完特定通行证销毁,从0到n问分别从每个房间出发能经过多少房间
面前有n+1个房间,n个门,门有两种:正数门需要你拥有对应数字的钥匙才能通过,负数门随便通过,但是会夺走对应数字的钥匙。问分别在0到n-1作为起点,各自走的最远距离。

//用right表示最远可达的位置,每次遇到负数,而且他的first数组的数字是一个非零数,就更新right的数值。

//最后因为right是最远可达位置,我们每次反向遍历中就可以让ans[time]=right-time;
const int MAXN=5e5+10;
//!!!!错误原因:语句顺序问题,在刚定义n还未输入时就初始化right为n
int a[MAXN],first[MAXN],ans[MAXN];
int main()
{
	int n;
	cin>>n;
	int right=n;
	for(int time=0;time<n;time++)cin>>a[time];
	for(int time=n-1;time>=0;time--)
	{
		if(a[time]>0)first[a[time]]=time;
		else
		{
			if(first[-a[time]]!=0)right=min(right,first[-a[time]]);
		}
		ans[time]=right-time;
	}
	for(int time=0;time<n;time++)cout<<ans[time]<<' ';
	cout<<endl;
	return 0;
}

//另一种解法
#include<iostream>
#include<stdio.h>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 5e5+10;
int a[maxn];
int pos[maxn];         //第一种类型的通道时,记录每种颜色出现的最早位置
int room[maxn];
int main()
{
	int n;
	while(cin>>n)
	{
		int i;
		int las = maxn + 1;
		for(i=1; i<=n; i++)
		{
			scanf("%d",&a[i]);
		}
		memset(pos,0,sizeof(pos));
		memset(room,0,sizeof(room));
		for(i=n; i>0; i--)
		{
			if(a[i]>0)
			{
				room[i] = room[i+1] + 1;
				pos[a[i]] = i;          //记录a[i]出现的最靠前的位置
			}
			else
			{
				if(!pos[-a[i]])
				{
					room[i] = room[i+1] + 1;     //如果在i后边没有这种颜色,可通过就是下一个情况加1。
				}
				else
				{
					las = min(las,pos[-a[i]]);       // 寻找能到达的最靠前的位置
					room[i] = las-i;
				}
			}
		}
		for(i=1; i<=n; i++)
		{
			if(i==1)
				printf("%d",room[i]);
			else
				printf(" %d",room[i]);
		}
		printf("\n");
	}
	return 0;
}

区间选取的贪心问题

同类问题
https://blog.csdn.net/memory_qianxiao/article/details/79966535
思路一样但是不会实现

翻译一段资料需要m个信息,信息分布在n本字典上,问这n本字典能否提供m个信息去翻译资料,若能得话,最少需要基本字典,并输出字典的序号。

首先按照左端点从小到大排序,左端点相同按照右端点从大到小排序。然后贪心选取,将设当前能到达的最远点为now,我们需要在左端点<=now+1的线段中选取右端点最大的放进去,之后更新now。其他不满足的情况特判即可。

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
vector<int>q;
struct node
{
	int l;
	int r;
	int id;
} p[200005];
bool cmp(node a,node b)
{
	if(a.l!=b.l)
		return a.l<b.l;
	else
		return a.r>b.r;
}
int main()
{
	int n,m,flag=0;
	cin>>n>>m;
	for(int i=1; i<=n; i++)
	{
		cin>>p[i].l>>p[i].r;
		p[i].id=i;
	}
	sort(p+1,p+1+n,cmp);
	if(p[1].l!=1)
		cout<<"NO"<<endl;

	else
	{
		q.push_back(p[1].id);
		int now=p[1].r;
		for(int i=2; i<=n;)
		{
			if(p[i].l>now+1)
			{
				cout<<"NO"<<endl;
				flag=1;
				break;
			}
			else
			{
				int temp=now,pos=p[i].id;
				while(i<=n&&p[i].l<=now+1)
				{
					if(p[i].r>temp)
					{
						temp=p[i].r;
						pos=p[i].id;
					}
					i++;
				}
				if(now==temp)
					continue;
				now=temp;
				q.push_back(pos);
			}
		}
		if(now<m&&flag==0)
			cout<<"NO"<<endl;
		else if(flag==0)
		{
			cout<<"YES"<<endl;
			cout<<q.size()<<endl;
			for(int i=0; i<q.size(); i++)
				cout<<q[i]<<' ';
			cout<<endl;
		}

	}
	return 0;
}
### 另一种写法

include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int maxn=200010;
struct node
{
int l,r,id;
}q[maxn];
int cmp(node a,node b)//按左端点从小到大,右端点从大到小排序
{
if(a.lb.l)return a.r>b.r;
return a.l<b.l;
}
vectorans;
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>q[i].l>>q[i].r;
q[i].id=i;
}
sort(q+1,q+1+n,cmp);
if(q[1].l!=1)return cout<<"NO"<<endl,0;
int now=q[1].r;
ans.push_back(q[1].id);//首先将第一条放进去
for(int i=2;i<=n;){
if(q[i].l>now+1)return cout<<"NO"<<endl,0;
else{
int temp=now,pos=q[i].id;
while(i<=n&&q[i].l<=now+1){//在当前now可连接的取右端点最大值
if(q[i].r>temp){
temp=q[i].r;
pos=q[i].id;
}
i++;
}
if(now
temp)continue;//防止不必要的放入
now=temp;
ans.push_back(pos);
}
}
if(now<m)return cout<<"NO"<<endl,0;
cout<<"YES"<<endl;
cout<<ans.size()<<endl;
for(int i=0;i<ans.size();i++){
cout<<ans[i]<<" ";
}
cout<<endl;
return 0;
}


  • 下午 vj团队4+vj3补题

vj4
https://vjudge.net/contest/642758#overview

清空队列

https://blog.csdn.net/qq_39424178/article/details/103358999

琐碎

!!!
sort函数时时
sort(coins,coins+N,greater());
注意还有括号!!!
!!

二分

题意:对于每组数据,找有多少组数据满足至少有两个比它小的
image
!!!最关键的转化,当x>y,不必枚举每一个元素,有另一种表达方式。有upeer大于搜索实现二分。

image

vector去重

//第一种set去重
int myints[] = {1,2,3,1,1};
    int len = sizeof(myints)/sizeof(int);
    vector<int> vec(myints, myints + len);
    set<int>s(vec.begin(), vec.end());
	//将vec中的所有元素复制到新创建的set容器s
    vec.assign(s.begin(), s.end());
	//将vec容器中的元素替换为set容器s中的元素,按照s中的顺序排列
    for(int x : vec)
        cout << x << ",";
    return 0;
	
//unique();
	//函数将相邻且重复的元素放到vector的尾部 然后返回指向第一个重复元素的迭代器再     用erase函数擦除从这个元素到最后元素的所有的元素。
	sort(vec.begin(), vec.end());
    vec.erase(unique(vec.begin(), vec.end()), vec.end());
	
//自带remove函数
	std::vector<int> vec(0);
    for(int i = 0 ; i < 10; i++)
    {
        vec.push_back(i);
        
    }
    vec.push_back(7);
    auto ret = std::remove(vec.begin(), vec.end(), 7);
    vec.erase(ret, vec.end());
	//删除特定元素
	//将它们移动到容器的末尾,并且返回一个新的迭代器ret,指向第一个被移动的元素(即第一个值为7的元素)的位置。

    for(auto &i : vec)
    {
        std::cout << i << " " << std::endl;
    }

vector的find()

对于一个存pair的vector我想找第一个元素为4的pair
image
find函数
find函数2

题解

https://blog.csdn.net/luker6/article/details/118581169


vj3补题+vj4补题(晚上)

涂色(贪心+规律)

题意:方阵a,b,b目前在a的左上角已涂色,问涂满a,求b中心移动的最小距离
!!!相对位置变化,不用看b的中心,看边就行。
(想的太麻烦了,又取余又整除的)
image

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
    int a,b;
    scanf("%d %d",&a,&b);
    ll tmp=a-b;
    ll ans=tmp;//初始是tmp,因为开始必须要走3个tmp,后面只用走2个
    while(tmp>0)
    {
        ans=ans+tmp+tmp;
        tmp-=b;
    }
    printf("%lld\n",ans);
    return 0;
}

以下vj4
vj4题解
https://www.cnblogs.com/Hamine/p/15940563.html
https://www.cnblogs.com/QLU-ACM/p/14682546.html

并查集(隐式应用)!!!

给定n对袜子(袜子保证有且只有两只,也就是保证数据一定合理)。我们可以把一些袜子放到洗衣机里面,但要保证这些袜子可以两两配对。让我们去求一次性最多可以弄多少双这样的袜子。

//数据比较大可以用哈希表来求,但是map速度有点慢,要用unordered_map,还有就是要用解除同步的cin和cout(scanf 和 printf 会超时)

#include <bits/stdc++.h>
 
using namespace std;
 
const int MAXN = 100050;
  
 
unordered_map <int,int> f, p;
int ans;
int n, m;
 
struct node {
    int x, y;
}q[MAXN];
 
int find(int x){
     if(f[x]==x)return x;
    else return f[x]=find(f[x]);
	//路径压缩
}
 
int main(){
      ios::sync_with_stdio(false);
    int t;
    cin >> t;
    while (t --){
        cin >> n;
        f.clear(), p.clear();
        for (int i = 1; i <= n; i++) cin >> q[i].x >> q[i].y, f[q[i].x] = q[i].x, f[q[i].y] = q[i].y;
        for (int i = 1; i <= n; i++){
            int a, b;
            a = q[i].x, b = q[i].y;
            if (find(a) != find(b))  f[find(b)] = f[find(a)];
			//仍然路径压缩
        }
        
        for (int i = 1; i <= n; i++){
            p[find(q[i].x)] ++;
			//在同一集合的父母相同,以此统计集合最大容量
			//因为最后要输出几对袜子不是几双袜子所以没有统计y
            ans = max(ans, p[find(q[i].x)]);
        }
        
        cout << ans << endl;
        ans = 0;
    }
        
}

map

map 适合于有序的键值对存储和需要快速查找、有序遍历的场景。
unordered_map 适合于不需要关心元素顺序,但需要快速查找、插入和删除的场景,尤其是对于大量数据的管理和查询操作。

map:查找、插入和删除操作的平均时间复杂度是** O(log n),其中 n 是 map 中元素的个数。
unordered_map:
查找、插入和删除操作的平均时间复杂度是 O(1)**,即常数时间复杂度,不过最坏情况下的复杂度为 O(n),其中 n 是 unordered_map 中元素的个数。这是因为哈希冲突可能导致链表或其他形式的线性探测。

map:底层实现是红黑树(balanced binary search tree),因此它的元素是按照键的大小进行排序的,默认情况下按照键的升序排列。
unordered_map:底层实现是哈希表(hash table),元素的存储顺序不固定,取决于元素的键的哈希值。因此,unordered_map 中的元素没有顺序上的关联,不能按照任何顺序(如升序或降序)进行迭代。

日期 (打表+前缀和)

给定t个样例,每个样例有两个日期(格式为Y,M,D,表示为年月日),输出两个日期之间的所有日期的年月日组成的字符串中含有"202"的日期的字符串的个数。

打表(补充)

类似于
month[]={31.28,31,30,31...};
dx={-1,0,1,0};
打表

时间计算问题补充

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define fir(i,a,n) for(int i=a;i<=n;i++)
const int N=1e5+10;
int n;
/*
202x xx xx
x202 xx xx
xxx2 02 xx
xxxx x2 02
*/
int a[8050][15][40];// i-2000 j k
int day[13]={0,31,29,31,30,31,30,31,31,30,31,30,31};
int run(int i)
{
	if((i%400==0||i%4==0)&&i%100!=0) return 1;
	else return 0;
}
int ju(int x)
{
	string a=to_string(x);
	//转化为字符串
	string f="202";
	int temp=a.find(f,0);
	//对字符串find找不到会返回-1;
	if(temp==-1) return 0;
	else  return 1;	
}
void solve()
{
	int last=0;
	for(int i=2000;i<=9999;i++)
	{
		for(int j=1;j<=12;j++)
		{
			for(int k=1;k<=day[j];k++)
			{
				if(j==2&&k==29&&!run(i)) continue;
				
				int temp=i*10000+j*100+k;
				
				if(ju(temp)) a[i-2000][j][k]=last+1;
				else a[i-2000][j][k]=last;
				last=a[i-2000][j][k];
			}
		}
	}
}
int main()
{
	int t;cin>>t;
	solve();	
	//因为有多个询问所以预处理
	while(t--)
	{
		int y,m,d,yy,mm,dd;
		scanf("%d%d%d%d%d%d",&y,&m,&d,&yy,&mm,&dd);
		int ans=a[yy-2000][mm][dd]-a[y-2000][m][d];
		//映射到a数组的合适位置
		int temp=y*10000+m*100+d;
		if(ju(temp)) ans++;
		//判断a是否满足202,因为ans不包括这天,减去了
		cout<<ans<<endl;
	}
	return 0;
}

posted on 2024-07-25 21:51  Hoshino1  阅读(3)  评论(0编辑  收藏  举报