【比賽】USACO21 Jan
【比賽】USACO21 Jan
文章目錄
Dec的時候進了Gold,於是這次只參加了Gold
P7296 [USACO21JAN] Uddered but not Herd G
題意:
給定字串s,試構造一種小寫字母排列p,使得將s劃分為若干組,每組字串均為p的子序列,且使得組數最少,輸出最少組數。
保證s長度小於等於1e5且s出現的不同字元不超過二十個
題解:
因為 ∣ p ∣ |p| ∣p∣很小,可以考慮狀壓DP
正難則反,考慮把每個字元劃分為一段
如果相鄰兩個字母在排列中順序就把他們合併起來
設 d p [ i ] dp[i] dp[i]表示當前的排列中已經選擇了的字母集合
更新時列舉下一個字母的選擇
對於在排列中出現過的字母如果在原串中位於當前字母之後
則他們無法合併,產生對答案的貢獻
可以先處理出每一對相鄰字母數量
記憶化搜尋即可
#include<bits/stdc++.h>
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;
}
P7297 [USACO21JAN] Telephone G
題意:
給定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<bits/stdc++.h>
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;
}
P7298 [USACO21JAN] Dance Mooves G
這題就只打了兩個部分分一共是50%的
題解就不寫了(咕咕咕)
等學會正解再來
u1s1這題是真的毒瘤
#include<bits/stdc++.h>
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應該會打一下
加油!