CF95
CF95A
CF95A题意
LSR \texttt{LSR} LSR 特别喜欢足球。有一天他做梦,梦到了自己变成某球队的教练。
现在 LSR \texttt{LSR} LSR 要给球队起名。球队已经有一个名字,是一个只含大小写字母的字符串 w w w。 LSR \texttt{LSR} LSR 的队伍有 n n n 名球员,每个人都有一个名字,它们不希望自己的名字出现在球队名称中(和队名中某一段字符串一样),所以 LSR \texttt{LSR} LSR 要用别的字母替换这些子串。
这里注意六点:
-
对于两个字符串一样,只需读音一样(即不区分大小写),也就是说 aBC \texttt{aBC} aBC 和 ABc \texttt{ABc} ABc 是一样的。
-
对于队名中的某一个字符 i i i,他替换的条件当且仅当存在 l , r ( 1 ≤ l ≤ i ≤ r ≤ ∣ w ∣ ) l,r(1 \leq l \leq i \leq r \leq \lvert w \rvert) l,r(1≤l≤i≤r≤∣w∣),使得 [ l , r ] [l,r] [l,r] 包含在队员名字里。如果 i i i 不在任何一个与名字重复的子串里,则它不能被更改。
-
队员们特别喜欢一个字母,因为队员们喜欢,所以你要使这个字母出现次数最多。如果有多种解,输出字典序最小的。
-
替换时要注意保留原字符串格式,即大小写。
-
更改时要注意每个字符都要用其他字符去更改,所以如果某个需要修改的字符和队员们喜欢的字符一样,则它需要修改成别的字符。
-
对于每次修改后形成的新串,如果因为修改出现了新的与队员名字一样的子串,则这个子串是不需要修改的。
CF95A题解
模拟慢慢写吧
CF95A代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 110;
int n;char S[maxn];
char a[maxn][maxn];
char opt;
bool book[maxn], chg[maxn];
char tolow(char ch){if(ch >= 'A' && ch <= 'Z')return ch - 'A' + 'a';return ch;}
char toup(char ch){if(ch >= 'a' && ch <= 'z')return ch - 'a' + 'A';return ch;}
signed main(){
scanf("%d",&n);
for(int i = 1;i <= n;i++){
scanf("%s",a[i] + 1);
for(int j = strlen(a[i] + 1);j;j--)a[i][j] = tolow(a[i][j]);
}
scanf("%s",S + 1);scanf(" %c",&opt);int len = strlen(S + 1);
for(int i = strlen(S + 1);i;i--){if(S[i] >= 'A' && S[i] <= 'Z'){book[i] = 1;S[i] = tolow(S[i]);}}
for(int i = 1;i <= len;i++){
for(int j = 1;j <= n;j++){
bool flag = 1;
for(int k = 1,l = strlen(a[j] + 1);k <= l;k++){
if(S[k + i - 1] != a[j][k]){flag = false;break;}
}
if(flag){for(int k = 1,l = strlen(a[j] + 1);k <= l;k++)chg[k + i - 1] = 1;}
}
}
opt = tolow(opt);
for(int i = 1;i <= len;i++){
if(chg[i]){
if(S[i] == opt){
if(S[i] == 'a')S[i] = 'b';
else S[i] = 'a';
}
else S[i] = opt;
}
}
for(int i = 1;i <= len;i++){
if(book[i])putchar(toup(S[i]));
else putchar(S[i]);
}
puts("");
return 0;
}
CF95C
CF95C题意
先给你一个有边权无向图( 1 ≤ n ≤ 1 0 3 1\le n\le10^3 1≤n≤103),然后每个节点有一对值 t , c t,c t,c,表示你可以以 c c c 花费走到任意一个距离这个点小于 t t t 的点,问从 S → T S\to T S→T 的最小花费
CF95C题解
读题读半天
发现点很少,直接每个节点跑一边kruskal然后暴力连边,在新图上跑一边kruskal就好了
CF95C代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
int x = 0, f =1;char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
return x * f;
}
const int maxn = 1100;
int n, m, S, T;
struct edge{
int to, nexte, wei;
edge(int to = 0,int ne = 0,int we = 0):to(to),nexte(ne),wei(we){}
}e[maxn * maxn * 2][2];
int tot[2],head[maxn][2];
void add(int u,int v,int w,int opt){e[++tot[opt]][opt] = edge(v,head[u][opt],w);head[u][opt] = tot[opt];}
struct node{
int first, second;
node(int f = 0,int s = 0):first(f),second(s){}
friend bool operator < (node a,node b){return a.first != b.first ? a.first < b.first : a.second < b.second;}
friend bool operator > (node a,node b){return a.first != b.first ? a.first > b.first : a.second > b.second;}
};
typedef priority_queue<node , vector<node> , greater<node> > prique;
int dis[maxn];bool book[maxn];
void kruskal(int S,int opt){
memset(dis,0x3f,sizeof(dis));memset(book,0,sizeof(book));
dis[S] = 0;prique que;que.push(node(dis[S],S));
while(!que.empty()){
int u = que.top().second;que.pop();
if(book[u])continue;book[u] = 1;
for(int i = head[u][opt];i;i = e[i][opt].nexte){
int v = e[i][opt].to, w = e[i][opt].wei;
if(dis[v] > dis[u] + w){
dis[v] = dis[u] + w;
que.push(node(dis[v],v));
}
}
}
}
signed main(){
n = read(); m = read(); S = read(); T = read();
int u, v, w;
for(int i = 1;i <= m;i++){
u = read(); v = read(); w = read();
add(u, v, w, 0); add(v, u, w, 0);
}
for(int i = 1;i <= n;i++){
kruskal(i, 0);
u = read(); v = read();
for(int j = 1;j <= n;j++)
if(dis[j] <= u){add(i,j,v,1);}
}
kruskal(S,1);
printf("%lld",dis[T] == 0x3f3f3f3f3f3f3f3f ? -1 : dis[T]);
return 0;
}
CF95E
CF95E题意
现在有一张
n
n
n 个点,
m
m
m 条边的无向图,给出幸运数的定义是数字所有位只有
4
4
4 或
7
7
7
问最少连多少条边可以使得有一个连通块含有的节点数量是一个幸运数
CF95E题解
发现一只野生的水紫题
首先先按照给出的边跑并查集,算出所有连通块的大小。
然后问题就变成了:有一个数组
a
1
,
2
,
.
.
.
,
t
o
t
a_{1,2,...,tot}
a1,2,...,tot,让你尽可能少的选择数字,使得其和是一个幸运数。
这玩应直接背包DP就完了~~~~~~~~吗?
O
(
n
2
)
O(n^2)
O(n2) 可不是闹着玩的。
注意到有一个性质,就是这个数组的和是
n
n
n。
所以如果将相同的数字合到一起变成多重背包DP的话,最多有
n
\sqrt{n}
n 个选择。
然后二进制优化一下就好了
怎么有人这玩应都能写挂啊(
CF95E代码
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x = 0, f =1;char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
return x * f;
}
const int maxn = 1e5 + 10;
int n, m;
int fa[maxn];
int getf(int x){return x == fa[x] ? x : fa[x] = getf(fa[x]);}
int siz[maxn], buc[maxn];
int cost[maxn], val[maxn], tot;
int f[maxn], ans = 0x3f3f3f3f;
void dfs(int u){
// printf("u = %d",u);
if(u * 10 + 4 > n)return;
u = u * 10 + 4;if(f[u] != 0x3f3f3f3f)ans = min(ans,f[u]);
dfs(u);u /= 10;
if(u * 10 + 7 > n)return;
u = u * 10 + 7;if(f[u] != 0x3f3f3f3f)ans = min(ans,f[u]);
dfs(u);
}
signed main(){
n = read(); m = read();
for(int i = 1;i <= n;i++){fa[i] = i;}
int u, v;
for(int i = 1;i <= m;i++){
u = getf(read()), v = getf(read());
if(u != v)fa[u] = v;
}
for(int i = 1;i <= n;i++)siz[getf(i)]++;
for(int i = 1;i <= n;i++)if(getf(i) == i){buc[siz[i]]++;}
for(int i = 1;i <= n;i++){
if(buc[i]){
for(int j = 0;j <= 30;j++){
if(buc[i] >= (1 << j)){
val[++tot] = (1 << j) * i;
cost[tot] = (1 << j);
buc[i] -= (1 << j);
}
}
if(buc[i] != 0){val[++tot] = buc[i] * i;cost[tot] = buc[i];}
}
}
memset(f,0x3f,sizeof(f));f[0] = 0;
for(int i = 1;i <= tot;i++)
for(int j = n;j >= val[i];j--)
f[j] = min(f[j],f[j - val[i]] + cost[i]);
// printf("tot=%d\n",tot);
// for(int i = 1;i <= tot;i++){printf("%d %d\n",cost[i],val[i]);}
// for(int i = 1;i <= n;i++)printf("f[%d]=%d,fa[i]=%d\n",i,f[i],fa[i]);
dfs(0);
printf("%d\n",ans == 0x3f3f3f3f ? -1 : (ans - 1));
return 0;
}