题意:
给定字符串s,试构造一种小写字母排列p,使得将s划分为若干组,每组字符串均为p的子序列,且使得组数最少,输出最少组数。
保证s长度小于等于1e5且s出现的不同字符不超过二十个
题解:
因为 ∣ p ∣ |p| ∣p∣很小,可以考虑状压DP
正难则反,考虑把每个字符划分为一段
如果相邻两个字母在排列中顺序就把他们合并起来
设 d p [ i ] dp[i] dp[i]表示当前的排列中已经选择了的字母集合
更新时枚举下一个字母的选择
对于在排列中出现过的字母如果在原串中位于当前字母之后
则他们无法合并,产生对答案的贡献
可以先处理出每一对相邻字母数量
记忆化搜索即可
#include
using namespace std;
inline int Read(){
int s = 0 , w = 1;
char ch = getchar();
while(ch > '9' || ch < '0'){
if(ch == '-') w = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9'){
s = (s << 1) + (s << 3) + ch - '0';
ch = getchar();
}
return s * w;
}
const int MAXN = 1e5 + 50;
char s[MAXN];
int a[MAXN];
int p[25][25];
int n;
int id[300],tot = 0;
int f[(1 << 21) + 10];
int DP(int ss){
if(ss == (1 << tot) - 1) return 0;
if(f[ss]) return f[ss];
int res = 0;
for(int i = 1 ; i <= tot ; i ++){
if((ss >> (i - 1)) & 1) continue;
int tmp = 0;
for(int j = 1 ; j <= tot ; j ++){
if((ss >> (j - 1)) & 1){
tmp += p[j][i];
}
}
res = max(res,tmp + DP((1 << (i - 1)) | ss));
}
return (f[ss] = res);
}
int main(){
scanf("%s",s + 1);
n = strlen(s + 1);
for(int i = 1 ; i <= n ; i ++){
if(!id[s[i]]) id[s[i]] = ++ tot;
a[i] = id[s[i]];
}
for(int i = 1 ; i + 1 <= n ; i ++){
p[a[i]][a[i + 1]] ++;
}
int ans = 0x3f3f3f3f;
for(int i = 1 ; i <= 20 ; i ++){
ans = min(ans,n - DP(1 << (i - 1)));
}
cout << ans << endl;
return 0;
}
题意:
给定n个点,每个点被分配k种颜色其中一种,任意两点 i , j i,j i,j距离定义为 ∣ i − j ∣ |i-j| ∣i−j∣,每种颜色的点向某些特定颜色的点连边(给定k*k个关系),求1到n的路径最小距离
颜色数量不多于20,n不多于5e4
题解:
这题应该是整场最easy的
看k的数据范围和求最短路就知道要建立分层图
还是比较明显的
我们按照以下步骤建图:
1.将每个点拆成k+1个点,k个点对应k个颜色,1个是本身
2.将k*n个点中每相同颜色的n个点相连,共连k层,双向边,边权为1
3.将每个点连接当前点颜色可到达的颜色对应的当前点拆出来的点,也将可到达当前点颜色的颜色对应的当前点拆出来的点连接当前点,边权均为0,单向边
最后跑从1到n的最短路即可
#include
using namespace std;
inline int Read(){
int s = 0 , w = 1;
char ch = getchar();
while(ch > '9' || ch < '0'){
if(ch == '-') w = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9'){
s = (s << 1) + (s << 3) + ch - '0';
ch = getchar();
}
return s * w;
}
const int MAXN = 60 * (5e4 + 50);
int n,k;
int a[MAXN],s[55][55];
int d[MAXN];
bool vis[MAXN];
priority_queue<pair<int,int> >Q;
int head[MAXN],to[MAXN << 1],nxt[MAXN << 1],val[MAXN << 1],tot;
void add(int x,int y,int v){
to[++tot] = y;
nxt[tot] = head[x];
head[x] = tot;
val[tot] = v;
}
int id(int i,int j){
return i * n + j;
}
void Dijkstra(int s){
memset(d,127,sizeof(d));
Q.push(make_pair(0,s));
d[s] = 0;
while(!Q.empty()){
int u = Q.top().second;
Q.pop();
if(vis[u]) continue;
vis[u] = true;
for(int i = head[u] ; i ; i = nxt[i]){
int v = to[i];
if(d[v] > d[u] + val[i]){
d[v] = d[u] + val[i];
Q.push(make_pair(-d[v],v));
}
}
}
}
int main(){
n = Read() , k = Read();
for(int i = 1 ; i <= n ; i ++) a[i] = Read();
for(int i = 1 ; i <= k ; i ++){
for(int j = 1 ; j <= k ; j ++){
char ch = getchar();
while(ch != '0' && ch != '1') ch = getchar();
s[i][j] = ch - '0';
}
}
for(int i = 1 ; i <= k ; i ++){
for(int j = 1 ; j + 1 <= n ; j ++){
add(id(i,j),id(i,j + 1),1);
add(id(i,j + 1),id(i,j),1);
}
}
for(int i = 1 ; i <= n ; i ++){
for(int j = 1 ; j <= k ; j ++){
if(s[a[i]][j]) add(i,id(j,i),0);
}
add(id(a[i],i),i,0);
}
Dijkstra(1);
if(d[n] < 0x7f7f7f7f) printf("%d\n",d[n]);
else printf("-1\n");
return 0;
}
这题就只打了两个部分分一共是50%的
题解就不写了(咕咕咕)
等学会正解再来
u1s1这题是真的毒瘤
#include
using namespace std;
#define int long long
inline int Read(){
int s = 0 , w = 1;
char ch = getchar();
while(ch > '9' || ch < '0'){
if(ch == '-') w = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9'){
s = (s << 1) + (s << 3) + ch - '0';
ch = getchar();
}
return s * w;
}
const int MAXN = 1e5 + 50;
int sp[MAXN << 1][2];
int n,m,k;
namespace A{
const int N = 100 + 5;
vector<int>vis[N],t[N];
int to[N],a[N];
bool wtb[N];
bitset<N>plc;
int res[N];
void solve(){
for(int i = 1 ; i <= n ; i ++){
a[i] = i;
vis[i].push_back(i);
t[i].push_back(0);
}
for(int i = 1 ; i <= k ; i ++){
vis[a[sp[i][0]]].push_back(sp[i][1]);
vis[a[sp[i][1]]].push_back(sp[i][0]);
t[a[sp[i][0]]].push_back(i);
t[a[sp[i][1]]].push_back(i);
swap(a[sp[i][0]],a[sp[i][1]]);
}
for(int i = 1 ; i <= n ; i ++){
to[a[i]] = i;
}
for(int i = 1 ; i <= n ; i ++){
memset(wtb,false,sizeof(wtb));
plc.reset();
int now = i;
// cout << i << ":" << endl;
for(int j = 0 ; j <= m && !wtb[now] ; now = to[now]){
if(wtb[now]) break;
wtb[now] = true;
// cout << now << endl;
if(j + k <= m){
for(int q = 0 ; q < vis[now].size() ; q ++){
plc[vis[now][q]] = 1;
}
j += k;
}
else{
for(int q = 0 ; t[now][q] + j <= m && q < vis[now].size() ; q ++){
plc[vis[now][q]] = 1;
}
// cout << plc << endl;
break;
}
}
res[i] = plc.count();
// cout << res[i] << endl;
}
for(int i = 1 ; i <= n ; i ++){
printf("%d\n",res[i]);
}
return;
}
}
namespace B{
vector<int>vis[MAXN];
int to[MAXN],a[MAXN];
bool wtb[MAXN];
bitset<MAXN>plc;
int res[MAXN];
int dfs(int x){
wtb[x] = true;
for(int i = 0 ; i < vis[x].size() ; i ++){
plc[vis[x][i]] = 1;
}
if(wtb[to[x]]){
// cout << plc << endl;
res[x] = plc.count();
return res[x];
}
res[x] = dfs(to[x]);
return res[x];
}
void solve(){
for(int i = 1 ; i <= n ; i ++){
a[i] = i;
vis[i].push_back(i);
}
for(int i = 1 ; i <= k ; i ++){
vis[a[sp[i][0]]].push_back(sp[i][1]);
vis[a[sp[i][1]]].push_back(sp[i][0]);
swap(a[sp[i][0]],a[sp[i][1]]);
}
for(int i = 1 ; i <= n ; i ++){
to[i] = a[i];
// cout << to[i] << " ";
}
// cout << endl;
for(int i = 1 ; i <= n ; i ++){
if(!wtb[i]){
plc.reset();
dfs(i);
}
}
for(int i = 1 ; i <= n ; i ++){
printf("%d\n",res[i]);
}
return;
}
}
#undef int
int main(){
#define int long long
n = Read() , k = Read() , m = Read();
for(int i = 1 ; i <= k ; i ++){
sp[i][0] = Read();
sp[i][1] = Read();
}
if(m > n * k){
B::solve();
}
else if(m <= 1e7){
A::solve();
}
else{
}
return 0;
}
USACO21JAN Result:
Bronze N/A
Silver N/A
Gold 833pts
Platinum N/A
成功拔掉flag,进Platinum啦,skr~
最后promotion cutoff是750pts , 833pts是 Gold #69
成功靠着两道AC和一道50%的部分分晋级啦!
Feb可能会咕掉但是US Open应该会打一下
加油!