今天打了一下SEERC2019,雖然做的很菜,但是題的質量真的不錯
I 簽到題(思維)
題意:
Alice和Bob玩取數遊戲,Alice每次從A序列中取出一個數字,Bob每次從B序列中取出一個數字,兩人輪流取數字,直到最後只剩下一個數字,Alice先手。Alice希望最後剩下的兩個數字差值的絕對值儘可能的小,Bob則相反,問如果兩人都取最佳策略,最後這個絕對值最大是多少?
分析與解答:
因爲兩個人的選取最佳策略,那麼無論Alice最後剩下數字爲多少,Bob一定會取到和它差值最小的那個,因此答案就是
代碼:
#include <cstdio>
#include <algorithm>
#define MAXN 1003
#include <cstring>
#include <cmath>
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;
}
D 構造+思維
題意:
給定一個長爲由小寫字母組成的序列,讓你找出這些字母構成的一個首尾相連的字符串,使得任何一個長度爲的子串不重複
分析與解答:
①出現次數最多的字母出現次數小於n,直接按照的順序依次排列下去
②出現次數最多的字母出現次數大於,這樣的字母最多有一個這時候分爲以下幾類:
①’如果僅有兩種字母,且另一種字母的出現次數小於,無法構造
②’設次數最多的字母爲,先放個,接着放一個其他字母,再把剩下的全部放完,後邊的放置方法同①
代碼
#include <cstdio>
#include <iostream>
#include <string>
#include <cstring>
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;
}
J 思維(圖論?)
題目:
給你一個爲奇數的完全圖,讓你從中找出一種邊的劃分使得每條邊有且僅屬於一個長度大於的環中(對於每個環,它的值爲相鄰兩條邊取最大權值的和),並且所有環的值的和最小,輸出這個最小值。
分析與解答:
我們考慮每個點的對答案的貢獻,對於相鄰的兩條邊來說,它們是靠一個點作爲銜接,也就是說對於一個點來說,與它連接的所有的邊一個是兩兩配對出現在一個環中的,因此答案就是將每個點的各個邊排序,然後兩兩配對,取大的那個權值。
代碼:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#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;
}
F
據說是一個樹形dp,待補題