2019牛客暑期多校训练营(第六场)G 暴力枚举+蔡勒公式

本文探讨了一种算法,用于验证由特定字符组成的日期格式是否合法,同时确保这些日期对应的是一周中的星期五。通过全排列的方式找到一组数字对应方案,使所有给定的日期字符串在转换后都符合规定的日期格式和星期要求。使用蔡勒公式进行日期合法性判断,通过剪枝和去重提高算法效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:T(T<=10)组样例,每次给出n(n<=1e5)个形如CABJ/AI/AC的只有'A’到‘J’之间字母构成的日期,

思路:合理分配0-9的全排列,使其依次对应‘A’到'J’之间的字母,使得分配后,n个日期都合法

所谓合法,这里是指满足基本日期限制条件下,年在[1600,9999]间,且该天为星期五

星期五的约束条件很严格,用蔡勒公式判,每次判几个就能把不合法的判掉。

#include<cstdio>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
string str[100010];
int day[13]={0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int a[15]={0,1,2,3,4,5,6,7,8,9};
int n;
int leap(int y)
{
	return ((y%4==0)&&(y%100!=0)||(y%400==0));
}
int find(int y,int m,int d)
{
	//剪枝 
	if(y<1600||y>9999)
	return 0;
	if(m<1||m>12)
	return 0;
	if(leap(y))
	{
		day[2]=29;
	}
	else
	{
		day[2]=28;
	}
	if(d<=0||d>day[m])
	return 0;
	if(m==1||m==2)
	{
		y--,m+=12;
	}
	return ((d+2*m+3*(m+1)/5+y+y/4-y/100+y/400)%7+1)==5?1:0;
}
int check()
{
	for(int i=1;i<=n;i++)//转换 
	{
		int y=0,m=0,d=0;
		for(int j=0;j<4;j++)
		y=y*10+a[str[i][j]-'A'];
		for(int j=5;j<7;j++)
		m=m*10+a[str[i][j]-'A'];
		for(int j=8;j<10;j++)
		d=d*10+a[str[i][j]-'A'];
		if(!find(y,m,d))
		{
			return 0;
		}
	}
	return 1;
}
int main()
{
	int t;
	cin>>t;
	int cas=1;
	while(t--)
	{
		cin>>n;
		for(int i=1;i<=n;i++)
		{
			cin>>str[i];
		}
		printf("Case #%d: ",cas++);
		sort(str+1,str+1+n);
		n=unique(str+1,str+1+n)-str-1;//去重 很重要
		for(int i=0;i<=9;i++)//!!!
		{
			a[i]=i;
		}
		int flag=0;
		do{
			if(check())
			{
				flag=1;
				for(int i=0;i<10;i++)
				cout<<a[i];
				cout<<endl;
				break;
			}
		}while(next_permutation(a,a+10));
		if(flag==0)
		{
			cout<<"Impossible"<<endl;
		}
	}
	return 0;
} 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值