今天打了一下SEERC2019,虽然做的很菜,但是题的质量真的不错
Alice和Bob玩取数游戏,Alice每次从A序列中取出一个数字,Bob每次从B序列中取出一个数字,两人轮流取数字,直到最后只剩下一个数字,Alice先手。Alice希望最后剩下的两个数字差值的绝对值尽可能的小,Bob则相反,问如果两人都取最佳策略,最后这个绝对值最大是多少?
因为两个人的选取最佳策略,那么无论Alice最后剩下数字为多少,Bob一定会取到和它差值最小的那个,因此答案就是 m a x { m i n { a i − b j } } max\{min\{a_i-b_j\}\} max{ min{ ai−bj}}
#include
#include
#define MAXN 1003
#include
#include
using namespace std;
long long a[MAXN],b[MAXN];
long long ans = 0;
int main()
{
int n;
scanf("%d",&n);
for(int i = 1;i <= n;i++)
scanf("%I64d",&a[i]);
for(int i = 1;i <= n;i++)
scanf("%I64d",&b[i]);
sort(a + 1,a + 1 + n);
for(int i = 1;i <= n;i++)
{
long long res = 2e9;
for(int j = 1;j <= n;j++)
res = min(abs(b[j] - a[i]),res);
ans = max(ans,res);
}
printf("%I64d\n",ans);
return 0;
}
给定一个长为 2 n 2n 2n由小写字母组成的序列,让你找出这些字母构成的一个首尾相连的字符串,使得任何一个长度为 n n n的子串不重复
①出现次数最多的字母出现次数小于n,直接按照 a … … a b … … b c … … c … … a……ab……bc……c…… a……ab……bc……c……的顺序依次排列下去
②出现次数最多的字母出现次数大于 n n n,这样的字母最多有一个这时候分为以下几类:
①’如果仅有两种字母,且另一种字母的出现次数小于 3 3 3,无法构造
②’设次数最多的字母为 a a a,先放 n n n个 a a a,接着放一个其他字母,再把剩下的 a a a全部放完,后边的放置方法同①
#include
#include
#include
#include
using namespace std;
string s;
int sum[30],n,tmp;
int main() {
memset(sum,0,sizeof(sum));
cin >> s;
int len = s.length(); n=len/2;
for (int i=0;i<len;i++) {
sum[s[i]-'a']++;
}
bool flag=true,ltn=false;
int t=0;
for (int i=0;i<26;i++) {
if (sum[i])
t++;
if (sum[i]>n) {
ltn=true;
tmp=i;
}
}
if (!ltn) {
printf("YES\n");
for (int i=0;i<26;i++) {
for (int j=1;j<=sum[i];j++) {
printf("%c",i+'a');
}
}
} else {
if (t==1) {
printf("NO\n");
} else if (t==2) {
if (len-sum[tmp]<=2) {
printf("NO\n");
} else {
printf("YES\n");
for (int i=1;i<=n;i++) {
printf("%c",tmp+'a');
}
for (int i=0;i<26;i++) {
if (sum[i] && i!=tmp) {
printf("%c",i+'a');
sum[i]--;
break;
}
}
for (int i=1;i<=sum[tmp]-n;i++) {
printf("%c",tmp+'a');
}
for (int i=0;i<26;i++) {
if (i!=tmp)
for (int j=1;j<=sum[i];j++) {
printf("%c",i+'a');
}
}
}
} else {
printf("YES\n");
for (int i=1;i<=n;i++) {
printf("%c",tmp+'a');
}
for (int i=0;i<26;i++) {
if (sum[i] && i!=tmp) {
printf("%c",i+'a');
sum[i]--;
break;
}
}
for (int i=1;i<=sum[tmp]-n;i++) {
printf("%c",tmp+'a');
}
for (int i=0;i<26;i++) {
if (i!=tmp)
for (int j=1;j<=sum[i];j++) {
printf("%c",i+'a');
}
}
}
}
return 0;
}
给你一个 n n n为奇数的完全图,让你从中找出一种边的划分使得每条边有且仅属于一个长度大于 2 2 2的环中(对于每个环,它的 v a l u e value value值为相邻两条边取最大权值的和),并且所有环的 v a l u e value value值的和最小,输出这个最小值。
我们考虑每个点的对答案的贡献,对于相邻的两条边来说,它们是靠一个点作为衔接,也就是说对于一个点来说,与它连接的所有的边一个是两两配对出现在一个环中的,因此答案就是将每个点的各个边排序,然后两两配对,取大的那个权值。
#include
#include
#include
#include
#define MAXN 1000005
typedef long long ll;
using namespace std;
ll ans=0;
bool vis[MAXN*2];
int tot,n,st;
struct Edge1 {
int u,v;
ll w;
}e[MAXN*2];
struct Edge {
int to,next;
ll w;
}edge[MAXN*2];
int head[MAXN];
void init() {
tot=0;
memset(head,-1,sizeof(head));
memset(vis,false,sizeof(vis));
}
void addedge(int u, int v, int w) {
edge[tot].to=v;
edge[tot].w=w;
edge[tot].next=head[u];
head[u]=tot++;
}
bool cmp(Edge1 e1, Edge1 e2) {
return e1.w<e2.w;
}
int main() {
init();
scanf("%d",&n);
for (int i=1;i<=n*(n-1)/2;i++) {
scanf("%d%d%lld",&e[i].u,&e[i].v,&e[i].w);
}
sort(e+1,e+1+n*(n-1)/2,cmp);
for (int i=1;i<=n*(n-1)/2;i++) {
addedge(e[i].u,e[i].v,e[i].w);
addedge(e[i].v,e[i].u,e[i].w);
}
for (int i=1;i<=n;i++) {
for(int j = head[i];~j;j=edge[j].next)
{
ans += edge[j].w;
j = edge[j].next;
}
}
cout << ans << endl;
return 0;
}
据说是一个树形dp,待补题