gym101669E Looping Playlist SEERC2017

https://codeforces.com/gym/101669/problem/E

猜了一下结论然而过了,有点惊喜。。。

首先把12种基调状态压缩预处理一下,然后高位前缀和维护一下超集,vis[mask]=true表示当前有的音调状态是存在某一种基调中的

然后我们知道给出的是环,所以我们把他拓展到2倍,然后找dp[i]-dp[i-n]就是截取这一段的最小值求出来就行了,求最小值就是i向后移动,然后mask更新,如果vis[mask]不行了,就说明[l,i]这一段不能再同一首歌中,所以l就要向右移动直到[l,i]可以在同一首歌中。

然后有个问题,如果dp[i-n]=dp[i-n+1],说明从a[i-n+1]到a[n]的开头是由dp[i-n]拓展过来的还是必须单独开一段,所以要+1,因为我每次都是直到某一个不行才换新的一段。其实这里我没想清楚,也证明不出,因为舍弃掉a[i-n]时,从a[i-n+1]开始可能可以向右到更右边,dp[i]可能会更小一些,但我怀疑这12种基调会完美地解决这个问题,就是舍掉一个向右走,还是一样会换新的一段,然后就过了233

用scanf超时了了一发,换了fread只要400ms,看wxh的博客发现他用cin取消同步读string,我试了一下我的变成了1000ms还是过了

wxh的做法更对一些,不用考虑12种基调的具体情况。只需要枚举开头是12种情况的哪一种,然后尽可能左右扩大以后,跑剩下的部分,复杂度变成了O(12*n)但是非常正确

#include<bits/stdc++.h>
using namespace std;

inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int rd(int &x){
    char c=nc(),f=1;
    for(;(c<'0'||c>'9')&&c!=EOF;c=nc()) if(c=='-') f=-1;
    if(c==EOF) return EOF;
    for(x=0;c>='0'&&c<='9';c=nc()) x=x*10+c-'0';
    x*=f;
    return 1;
}
inline int blank(char ch){
    return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';
}
inline int rd(char *s){
    char c=nc();
    while(blank(c)) c=nc();
    if(c==EOF) return EOF;
    for (;!blank(c)&&c!=EOF;c=nc())*s++=c;
    *s=0;
    return 1;
}
const int maxl=2e7+10;

int n,ans;
int a[maxl],dp[maxl];
bool vis[maxl];
char s[100];
int tx[12]={0,2,4,5,7,9,11,12};
int num[12];

inline void prework()
{
	//scanf("%d",&n);
	rd(n);
	int l;
	for(int i=1;i<=n;i++)
	{
		//scanf("%s",s);
		rd(s);
		l=strlen(s);
		if(s[0]=='D')
			a[i]= (l==2)?0:1;
		if(s[0]=='R')
			a[i]= (l==2)?2:3;
		if(s[0]=='M')
			a[i]=4;
		if(s[0]=='F')
			a[i]= (l==2)?5:6;
		if(s[0]=='S' && s[1]=='o')
			a[i]= (l==3)?7:8;
		if(s[0]=='L')
			a[i]= (l==2)?9:10;
		if(s[0]=='S' && s[1]=='i')
			a[i]=11;
	}
	for(int i=n+1;i<=2*n;i++)
		a[i]=a[i-n];
	int mask,d;
	for(int i=0;i<12;i++)
	{
		mask=1<<i;
		for(int j=1;j<=7;j++)
		{
			d=(i+tx[j])%12;
			mask|=1<<d;
		}
		vis[mask]=true;
	}
	for(int j=0;j<12;j++)
		for(int i=0;i<(1<<12);i++)
		if(!(i&(1<<j)))
			vis[i]|=vis[i|(1<<j)];
}

inline void mainwork()
{
	int mask=0,l=1;
	for(register int i=1;i<=2*n;++i)
	{
		if(num[a[i]]==0)
			mask|=1<<a[i];
		num[a[i]]++;
		while(!vis[mask] || l<=i-n)
		{
			num[a[l]]--;
			if(!num[a[l]])
				mask^=1<<a[l];
			l++;
		}
		dp[i]=dp[l-1]+1;
	}
	ans=dp[n];
	for(register int i=n+1;i<=2*n;++i)
	{
		if(dp[i-n]==dp[i-n+1])
			ans=min(ans,dp[i]-dp[i-n]+1);
		else
			ans=min(ans,dp[i]-dp[i-n]);
	}
}

inline void print()
{
	printf("%d",ans);
}

int main()
{
	prework();
	mainwork();
	print();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/liufengwei1/article/details/108945760