2021-2022 ACM-ICPC Latin American Regional Programming Contest


前言

vp补题


F. Fields Division

题意:存双向边的图,从n-1开始向前走,直到不能走为止,这条路为Bob的。没有经过的点是Alice的。

coding

void dfs(int x)
{
    vis[x] = 1;
    for(auto v : g[x])
    {
        if(v == n) continue;
        if(!vis[v]) dfs(v);
    }
}
 
void solve(){
    IOS;
    cin >> n >> m;
    rep(i, m)
    {
        int u, v;
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dfs(n - 1);
    rep(i, n)
    {
        if(vis[i]) cout << 'B';
        else cout << 'A';
    }
}

H.待补

I. Invested Money

题意:给定今天是星期几和存了几天钱,以及每次存钱距离今天多少天。
每次存的钱都是30天定期,只有到期且是**周一到周五才能进行取钱或者是进行续存服务**
问:最近一次能够去到一次钱距离今天几天?
//代码最好简洁整齐,方便debug
思路:1->3->5->1
2->4->6->1
3->5->7->1
4->6->1
5->7->1
题目保证不会存款不会在周六周日
能够发现周期是1->3->5,那么处理完周期外的天数就能够按照周期进行了。

coding

int a[N];
void solve()
{
	string s;
	cin>>s;
	int now=0;
	if(s=="Mon")now=1;
	else if(s=="Tue")now=2;
	else if(s=="Wed")now=3;
	else if(s=="Thu")now=4;
	else if(s=="Fri")now=5;
	else if(s=="Sat")now=6;
	else if(s=="Sun")now=0;
	int n;
	scanf("%d",&n);
	int ans=inf;
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		int start=(now-a[i]%7+7)%7;
		int flag=0;
		if(a[i] == 0)flag=1;
		if(start==2){
			if(a[i]>=62){
				a[i]-=62;
				start=1;
			}
			else if(a[i]>=30){
				a[i]-=30;
				start=4;
			}
		}
		else if(start==3){
			if(a[i]>=61){
				a[i]-=61;
				start=1;
			}
			else if(a[i]>=30){
				a[i]-=30;
				start=5;
			}
		}
		else if(start==4){
			if(a[i]>=32){
				a[i]-=32;
				start=1;
			}
		}
		else if(start==5){
			if(a[i]>=31){
				a[i]-=31;
				start=1;
			}
		}
		a[i]%=91;
		while(a[i] > 0) {
			if(start == 1) {
				start = 3;
				a[i] -= 30;
			} else if(start == 2) {
				start = 4;
				a[i] -= 30;
			} else if(start == 3) {
				start = 5;
				a[i] -= 30;
			} else if(start == 4) {
				start = 1;
				a[i] -= 32;
			} else if(start == 5) {
				start = 1;
				a[i] -=31;
			}
		}
		if(flag) {
			if(start == 5) a[i] =31;
			else if(start == 4) a[i] = 32;
			else a[i] = 30;
		}
		ans=min(ans,abs(a[i]));
	}
	printf("%d\n",ans);
}

Grittyb’s coding

//更简洁易懂些
int a[N];
int val[8], to[8];
int Anow=0;
string s;
void init() {
  if(s=="Mon")Anow=1;
  else if(s=="Tue")Anow=2;
  else if(s=="Wed")Anow=3;
  else if(s=="Thu")Anow=4;
  else if(s=="Fri")Anow=5;
  else if(s=="Sat")Anow=6;
  else if(s=="Sun")Anow=7;
  to[1] = 3, val[1] = 30;
  to[2] = 4, val[2] = 30;
  to[3] = 5, val[3] = 30;
  to[4] = 1, val[4] = 32;
  to[5] = 1, val[5] = 31;
}
int main(int argc, char const *argv[])
{ 
  init_code();
  cin>>s;
  init();
  int n;
  scanf("%d",&n);
  int ans=INF;
  for(int i=1;i<=n;i++){
    scanf("%d",&a[i]);
    int y = a[i] % 7;
    int now = Anow;
    if(now > y) now -= y;
    else now =  now + 7 - y;
    int re = 0;
    if(a[i] == 0) {
       re = val[now];
    } else {
       while(now != 1 && re < a[i]) {
          re += val[now];
          now = to[now];
       }
       if(re < a[i])re += (a[i] - re) / 91 * 91;
       while(re < a[i]) {
         re += val[now];
         now = to[now];
       }
    }
     ans = min(ans, re - a[i]);
  }
  printf("%d\n",ans);
 
  return 0;
}

J. Joining Pairs

题意:给定平面内的几条线段的两端点,将线段能够随意弯曲(平面内)
问:是否能够使得所有的线段不相交?
思路:如果线段的的两端点都在平面的边界上,那么平面一定会被分割成两个平面。
如果另一条线段的端点分别在两个平面的边界上,那么一定会产生交点,那么一定不符合条件。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

显然绿色的会产生交点,而紫色的不会产生交点。
在这里插入图片描述

此当产生交点时可以看出如果我们按照一个顺序存放所有的端点,那么两条线段的端点会有前后顺序,利用括号匹配的写法进行同一线段匹配,最后判断栈是否为空就能够判断是否有交点了。

coding

//直接cin输入会T
vector<PII>up,dw,le,ri;
vector<int>all;
stack<int>st;
int h,w,n,cnt=0;
 
bool check(int a,int b)
{
	if(a==0||a==h||b==0||b==w)return 1;
	else return 0;
}
 
void add(int a,int b){
	if(a==0)up.push_back({b,cnt});
	else if(a==h)dw.push_back({b,cnt});
	else if(b==0)le.push_back({a,cnt});
	else if(b==w)ri.push_back({a,cnt});
}
 
void solve()
{
	scanf("%d%d%d",&h,&w,&n);
	for(int i=1;i<=n;i++){
		int a1,b1,a2,b2;
		scanf("%d %d %d %d",&a1,&b1,&a2,&b2);
		if(check(a1,b1)&&check(a2,b2)){
			cnt++;
			add(a1,b1);
			add(a2,b2);
		}
	}
	sort(up.begin(),up.end());
	sort(dw.begin(),dw.end());
	sort(le.begin(),le.end());
	sort(ri.begin(),ri.end());
	for(int i=0;i<up.size();i++)
		all.push_back(up[i].second);
	for(int i=0;i<ri.size();i++)
		all.push_back(ri[i].second);
	for(int i=dw.size()-1;i>=0;i--)
		all.push_back(dw[i].second);
	for(int i=le.size()-1;i>=0;i--)
		all.push_back(le[i].second);
	for(int i=0;i<all.size();i++){
		if(!st.empty()&&st.top()==all[i])st.pop();
		else st.push(all[i]);
	}
	if(st.empty())printf("Y\n");
	else printf("N\n");
}

K.KIARA is a Recursive Acronym

题意:只能用给定所有字符串的首字母,问能否组成给定字符串中的某一个字符串。

coding

//输入必须优化
void solve(){
    IOS;
    int n;
    cin >> n;
    rep(i, n)
    {
        cin >> s[i];
        int k = s[i][0] - 'A';
        a[k]++;
    }
    rep(i, n)
    {
        int f = 1;
        for(int j = 0; j < s[i].size(); j++)
        {
            if(a[s[i][j] - 'A'] == 0){
                    f = 0;
                    break;
            }
        }
        if(f)
        {
            printf("Y");
            return;
        }
    }
    printf("N");
}

M. Most Ordered Way

题意:有n个事件,每个事件有完成花费的时间和结束的最后期限
问:是否能够按时完成所有的事件,如果能完成使得完成的事件的字典序排列尽量小
思路:首先利用最后期限排序后特判是否能够按时完成所有事件
那么关键就是能够完成时找最小字典序排列,也就是并发执行事件时尽可能事件编号小的先进行。
直接O(n2)复杂度能过,而O(n2logn)不能过。

coding

struct thing{
	int cost,deadline,idx;
}th[5100];
 
bool vis[5100];
 
void solve()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>th[i].cost>>th[i].deadline;
		th[i].idx=i;
	}
	sort(th+1,th+n+1,[](thing &a,thing &b){
		return a.deadline<b.deadline;
	});
	 ll sum=0;
	 for(int i=1;i<=n;i++){
	 	if(sum+th[i].cost>th[i].deadline){
	 		printf("*");
	 		return;
	 	}
	 	sum+=th[i].cost;
	 }
	 ll now=0;
	 int num=n;
	 while(num>0){
	 	int j=-1,maxn=1e9+1;
	 	ll s2=now;
	 	for(int i=1;i<=n;i++){
	 		if(vis[i])continue;
	 		if(maxn>=th[i].cost&&(j==-1||th[i].idx<th[j].idx))j=i;
	 		s2+=th[i].cost;
	 		maxn=min(maxn*1ll,th[i].deadline-s2);
	 	}
	 	now+=th[j].cost;
	 	printf("%d ",th[j].idx);
	 	num--;
	 	vis[j]=1;
	 }
 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值