7

USACO一月月赛金组游记

 3 years ago
source link: https://blog-e.tk/2021/01/24/USACO%E4%B8%80%E6%9C%88%E6%9C%88%E8%B5%9B%E9%87%91%E7%BB%84%E6%B8%B8%E8%AE%B0/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
USACO一月月赛金组游记 - Blog E

上来一看这题蒙了,猜了几个结论,又打了个贪心,结果只过了样例,就先去打 T2 了。

打完 T2 回到这题,仔细想想,发现这个答案是很难直接在输入字符串序列上 dp 的,故考虑构造牛文字母表的顺序,使得结果最小。

先跳过构造的过程,假设我们目前已经知道,牛文字母表的顺序就是 abcdefg… 我们如何快速的求出输入序列的答案呢?

不妨设输入序列为abcba,我们发现这个序列最少需要唱3次才能出现,为什么呢?唱第一次可以出现到abc但是下一项b的字典序比c靠前,所以b就只能再唱一次了,下一项a也是同理,所以这个序列的答案是 3 。

总结一下,答案为:

1+∑i∈[1,n−1](dict[str[i]]>=dict[str[i+1]])1+∑i∈[1,n−1](dict[str[i]]>=dict[str[i+1]])

其中 dict[x] 表示 x 字符在牛文字母表中排在第几个

现在我们要构造一个牛文序列,26! 的算法肯定是不行的,但是观察数据范围我们发现暗藏玄机:

  • 测试点 6-16 中,Farmer Nhoj 从未听到任何出现在 Mildred 名字中的字母。

也就是说字符集只有 20 个,是可以状压 dp 的。

于是我们从小到大构造一个牛文字母表,dp[s] (s是状压出来的数)表示当前构造的字母表中,已经包含了 s 这些字符的时候,答案的最小值。

采用“我为人人”的 dp 方式,当我们新加入一个字符 x 的时候,如何计算答案会增加多少呢?

我们只需知道有多少个 i 满足 (str[i]==x) and str[i+1]∈(s∪{x})(str[i]==x)andstr[i+1]∈(s∪{x}),于是我开了个桶并暴力实现这个,详见代码

此题复杂度 O(220×202)O(220×202)

#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define rd scanf
#define pt printf
#define setp(x) setprecision(x)
#define mem(x,y) memset(x,y,sizeof(x))
#define sz(x) (int)x.size()
#define umn(x,y) x=min(x,y)
#define umx(x,y) x=max(x,y)
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll,ll> pi;
typedef vector<ll> vi;
typedef vector<pi> vpi;

const double eps=1e-9;
const ll INF=1e18;
const ll P=998244353;
const ll MXN=1e5+5;

inline ll mod(ll x){return x>=P?x-P:x;}
inline ll mul(ll x,ll y){if(x<y)swap(x,y);ll res=0;while(y){if(y&1)res=mod(res+x);x=mod(x<<1);y>>=1;}return res;}
inline ll qpow(ll x,ll y){ll res=1;while(y){if(y&1)res=res*x%P;x=x*x%P;y>>=1;}return res;}
ll gcd(ll x,ll y){return !y?x:gcd(y,x%y);}
inline void pbin(ll x,ll y){for(;~y;y--)cerr<<char('0'+((x>>y)&1));cerr<<endl;}



const int CSZ=26;
const int MXSZ=20;
ll n;
char str[MXN];
ll cnt[MXSZ][MXSZ];
ll dp[1<<MXSZ];
ll table[CSZ],sz;


#define toi(x) table[(x)-'a']



inline void solve(){
    //codes
	cin>>(str+1);
	n=strlen(str+1);
	mem(table,-1);
	for(int i=1;i<=n;i++)
		if(toi(str[i])==-1)
			toi(str[i])=sz++;

	for(int i=1;i<n;i++)
		cnt[toi(str[i])][toi(str[i+1])]++;

	mem(dp,0x3f);
	dp[0]=1;
	for(int i=0;i<(1<<sz);i++){
		/*pbin(i,5);
		cout<<dp[i]<<endl;*/
		for(int j=0;j<sz;j++)
			if(!((i>>j)&1)){
				ll tmp=dp[i]+cnt[j][j];
				for(int k=0;k<sz;k++)
					if((i>>k)&1)
						tmp+=cnt[j][k];
				umn(dp[i^(1<<j)],tmp);
			}
	}
	cout<<dp[(1<<sz)-1];


}
int main(){
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	ios_base::sync_with_stdio(0);cin.tie(0);
	cout<<setiosflags(ios::fixed);
	srand(time(NULL));

	solve();
	return 0;
}

打了一个裸的 spfa,得到92分的好成绩

#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define rd scanf
#define pt printf
#define setp(x) setprecision(x)
#define mem(x,y) memset(x,y,sizeof(x))
#define sz(x) (int)x.size()
#define umn(x,y) x=min(x,y)
#define umx(x,y) x=max(x,y)
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll,ll> pi;
typedef vector<ll> vi;
typedef vector<pi> vpi;

const double eps=1e-9;
const ll INF=1e18;
const ll P=998244353;
const ll MXN=1e5+5;
const ll MXK=55;

inline ll mod(ll x){return x>=P?x-P:x;}
inline ll mul(ll x,ll y){if(x<y)swap(x,y);ll res=0;while(y){if(y&1)res=mod(res+x);x=mod(x<<1);y>>=1;}return res;}
inline ll qpow(ll x,ll y){ll res=1;while(y){if(y&1)res=res*x%P;x=x*x%P;y>>=1;}return res;}
ll gcd(ll x,ll y){return !y?x:gcd(y,x%y);}
inline void pbin(ll x,ll y){for(;~y;y--)cerr<<char('0'+((x>>y)&1));cerr<<endl;}



ll n,k;
ll dis[MXN],tp[MXN];
vi ec[MXK],ek[MXK];
bool inq[MXN];
inline void spfa(){
	mem(dis,0x3f);
	deque<ll> q;
	q.push_front(1);
	dis[1]=0;
	while(!q.empty()){
		ll p=q.front();
		q.pop_front();
		inq[p]=0;
		int ctp=tp[p];
		for(int i=0;i<sz(ek[ctp]);i++){
			int ntp=ek[ctp][i];
			for(int j=0;j<sz(ec[ntp]);j++){
				int nc=ec[ntp][j];
				int nw=dis[p]+abs(nc-p);
				if(nw<dis[nc]){
					dis[nc]=nw;
					if(!inq[nc]){
						inq[nc]=1;
						q.empty() || dis[nc]<=dis[q.front()] ? q.push_front(nc):q.push_back(nc);
					}
				}
			}
		}
	}
}
inline void solve(){
    //codes
	cin>>n>>k;
	for(int i=1;i<=n;i++){
		cin>>tp[i];
		ec[tp[i]].pb(i);
	}
	for(int i=1;i<=k;i++){
		char str[MXK];
		cin>>(str+1);
		for(int j=1;j<=k;j++)
			if(str[j]=='1')
				ek[i].pb(j);
	}
	spfa();
	cout<<(dis[n]<1e16?dis[n]:-1);
}
int main(){
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	ios_base::sync_with_stdio(0);cin.tie(0);
	cout<<setiosflags(ios::fixed);
	srand(time(NULL));

	solve();
	return 0;
}

打了一个暴力,得到 25 分的好成绩,时间不太够,懒得想 50 分了,听说 50 分是银组 T1。

#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define rd scanf
#define pt printf
#define setp(x) setprecision(x)
#define mem(x,y) memset(x,y,sizeof(x))
#define sz(x) (int)x.size()
#define umn(x,y) x=min(x,y)
#define umx(x,y) x=max(x,y)
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll,ll> pi;
typedef vector<ll> vi;
typedef vector<pi> vpi;

const double eps=1e-9;
const ll INF=1e18;
const ll P=998244353;
const ll MXN=200+5;

inline ll mod(ll x){return x>=P?x-P:x;}
inline ll mul(ll x,ll y){if(x<y)swap(x,y);ll res=0;while(y){if(y&1)res=mod(res+x);x=mod(x<<1);y>>=1;}return res;}
inline ll qpow(ll x,ll y){ll res=1;while(y){if(y&1)res=res*x%P;x=x*x%P;y>>=1;}return res;}
ll gcd(ll x,ll y){return !y?x:gcd(y,x%y);}
inline void pbin(ll x,ll y){for(;~y;y--)cerr<<char('0'+((x>>y)&1));cerr<<endl;}



ll n,m,k;
pi arr[MXN],suf[MXN];
ll last[MXN];

bool vis[MXN],cc[MXN][MXN];
inline void cal(ll x){
	mem(vis,0);
	mem(cc,0);

	ll ans=1,ct=last[x],tot=last[x];
	vis[x]=1,cc[0][x]=1;
	while(tot<=m && !cc[ct][x]){
		cc[ct][x]=1;
		if(!vis[x]){
			ans++;
			vis[x]=1;
		}
		if(x==arr[ct].fi){
			x=arr[ct].se;
			ll nx=suf[ct].se;
			tot+=nx-ct<=0?nx-ct+k:nx-ct;
			ct=nx;
		}
		else{
			x=arr[ct].fi;
			ll nx=suf[ct].fi;
			tot+=nx-ct<=0?nx-ct+k:nx-ct;
			ct=nx;
		}
	}
		if(!vis[x]){
			ans++;
			vis[x]=1;
		}
	cout<<ans<<endl;
}


inline void solve(){
    //codes
	cin>>n>>k>>m;
	for(int i=1;i<=k;i++)
		cin>>arr[i].fi>>arr[i].se;
	for(int i=k;i;i--){
		suf[i].fi=last[arr[i].fi];
		suf[i].se=last[arr[i].se];
		last[arr[i].fi]=last[arr[i].se]=i;
	}
	for(int i=k;i;i--){
		suf[i].fi=last[arr[i].fi];
		suf[i].se=last[arr[i].se];
		last[arr[i].fi]=last[arr[i].se]=i;
	}
	for(int i=1;i<=n;i++)cal(i);
}
int main(){
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	ios_base::sync_with_stdio(0);cin.tie(0);
	cout<<setiosflags(ios::fixed);
	srand(time(NULL));

	solve();
	return 0;
}

作者:@ethan-enhe
本文为作者原创,转载请注明出处:本文链接

阅读量 69


ee4b399fb99b3f7104668fc2be8b25a3?d=identicon&v=1.4.4
ethan_enhe Edge 88.0.705.50 Windows 10.0
2021-01-28回复

。。。差一个测试点晋级。。。

ee4b399fb99b3f7104668fc2be8b25a3?d=identicon&v=1.4.4
ethan_enhe Edge 88.0.705.50 Windows 10.0
2021-01-28回复

@ethan_enhe , 我佛了

Powered By Valine
v1.4.4

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK