1. 程式人生 > 其它 >【比賽】USACO21 Jan

【比賽】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| ij,每種顏色的點向某些特定顏色的點連邊(給定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應該會打一下

加油!