Contest 210205

题目已存档至硬盘

万能遥控器

第一道就是毒瘤模拟,TAT.先不改了,记录一下我的代码和标程吧.

#include <bits/stdc++.h>

using namespace std;
int n;
char ip[100][50],ans[100][50];
string s;

inline int read()
{
	int s=1,x=0;char c=getchar();
	while(c>'9'||c<'0'){if(c=='-')s=0;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+c-48;c=getchar();}
	return s?x:-x;
}

bool special(int &len)
{
	for(int i=0;i<len-2;i++)
	{
		if(s[i]==':'&&s[i+1]==':'&&s[i+2]==':')
			return true;
	}
	return false;
}

void solve()
{
	for(int j=0;j<100;j++)
		{
			for(int k=0;k<50;k++)
			{
				ip[j][k]='x';
				ans[j][k]='x';
			}
		}
		cin>>s;
		int len=s.length(),flag=-1,p=0,p_group=-1;
		if(special(len))
		{
			cout<<"INVALID\n";
			return;
		}
		for(int j=0;j<len;j++)
		{
			if(j<len-1&&s[j]==':'&&s[j+1]==':')
			{
				if(flag==-1)
					flag=p;	
				else
				{
					cout<<"INVALID\n";
					return;
				}
				p++;
				j++;
				p_group=-1;
			}
			else if(s[j]==':')
			{
				p++;
				p_group=-1;
			}
			else
				ip[p][++p_group]=s[j];
		}
		if((p<7&&flag==-1) || p>7 || (p==6 && flag>=0))
		{
			cout<<"INVALID\n";
			return;
		}
		for(int j=0;j<=p;j++)
		{
			int tot=0;
			for(int k=0;k<50;k++)
			{
				if(ip[j][k]=='x') break;
				else if((ip[j][k]>='0'&&ip[j][k]<='9') || (ip[j][k]>='A'&&ip[j][k]<='F'))
				{
					tot++;
				}
				else
				{
					cout<<"INVALID\n";
					return;
				}
			}
			if(tot>4)
			{
				cout<<"INVALID\n";
				return;
			}
			else
			{
				for(int k=0;k<4-tot;k++)
				{
					ans[j][k]='0';
				}
				for(int k=4-tot;k<4;k++)
				{
					ans[j][k]=ip[j][k-4+tot];
				}
			}
		}
		for(int j=0;j<=p;j++)
		{
			for(int k=0;k<4;k++)
			{
				if(ans[j][k]=='x')
				{
					cout<<"INVALID\n";
					return;
				}
				cout<<ans[j][k];
			}
			if(j!=p) cout<<':';
			if(j==flag)
			{
				for(int k=1;k<=(7-p);k++)
				{
					printf("0000");//bug,but solved
					if(k+j!=7) putchar(':');
				}
			}
		}
		cout<<endl;
}

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		solve();
	}
	
	return 0;
}

137行,学OI来写的最多的一次.

标程:

#include <bits/stdc++.h>
using namespace std;
char s[100], a[100];
int main()
{
	freopen( "ipv6.in", "r", stdin ); freopen( "ipv6.out", "w", stdout ); int n;
	scanf( "%d\n", &n );
	for ( int ii = 1; ii <= n; ii++ )
	{
		memset( s, '0', sizeof(s) );
		memset( a, '0', sizeof(a) );
		char	c;
		int	p1 = 0, p2 = 0, p3 = 0, p4 = 0, k = 0, point = 0;
		while ( (c = getchar() ) != EOF && c != '\n' )
		{
			s[++k] = c;
			if ( c == ':' )
			{
				p1 = 0; p2++;
			}else p1++;
			if ( p1 > 4 || p2 > 7 )
				p4 = 1;
			if ( c == ':' && s[k - 1] == ':' )
			{
				p3++; point = k;
			}
			if ( p3 > 1 )
				p4 = 1;
		}
		if ( !p3 && p2 < 7 )
			p4 = 1;
		if ( p3 && p2 == 7 && point != 2 && point != k )
			p4 = 1;
		for ( int i = 1; i <= k; i++ )
			a[i] = s[k - i + 1];
		if ( p4 )
		{
			printf( "INVALID\n" ); continue;
		}
		int q = 0;
		p1 = 0;
		for ( int i = 1; i <= k; i++ )
		{
			s[++q] = a[i];
			p1++;
			if ( a[i] == ':' )
			{
				q--;
				while ( p1 < 5 )
				{
					s[++q] = '0';
					p1++;
				}
				s[++q]	= ':';
				p1	= 0;
				if ( a[i + 1] == ':' )
				{
					while ( p2 <= 7 )
					{
						for ( int j = 1; j <= 4; j++ )
							s[++q] = '0';
						s[++q] = ':';
						p2++;
					}
					q--;
					p1 = 4;
				}
			}
		}
		for ( int i = 39; i >= 1; i-- )
			printf( "%c", s[i] );
		cout << endl;
	}
	return(0);
}

收藏钻石

这道题很有意思呀,乍一看以为是二分答案,结果要分成2个陈列架.然后想到用一块板子将钻石们分开,左右2边分别二分答案,但这样复杂度是 O ( n 2 l o g   n ) O(n^2 log\ n) O(n2log n).考虑优化,首先第一层枚举板子的循环肯定不能再优化了,难道优化二分答案?

结果真的是优化二分答案,考场上想出了一种DP方案.
若 m 表 示 所 有 满 足 a [ i ] − a [ i − m ] ≤ k 的 m 的 最 小 值 , 则 f [ i ] = m a x ( f [ i − 1 ] , m + 1 ) 若m表示所有满足a[i]-a[i-m]\le k的m的最小值,则\\f[i]=max(f[i-1],m+1) ma[i]a[im]km,f[i]=max(f[i1],m+1)
然后正向和反向分别DP一次,再插板,即可求出最终答案.

#include <bits/stdc++.h>

using namespace std;
const int N=5e4+5;
int n,k,s[N],ans,l[N],r[N];

inline int read()
{
	int s=1,x=0;char c=getchar();
	while(c>'9'||c<'0'){if(c=='-')s=0;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+c-48;c=getchar();}
	return s?x:-x;
}


int main()
{
	freopen("diamond.in","r",stdin);
	freopen("diamond.out","w",stdout);
	
	n=read();
	k=read();
	for(int i=1;i<=n;i++)
	{
		s[i]=read();
	}
	sort(s+1,s+n+1);
	
	l[1]=r[n]=1;
	l[0]=r[n+1]=0;
	for(int i=2;i<=n;i++)
	{
		int x=l[i-1];
		while(s[i]-s[i-x+1]<=k&&i-x>=0)
		{
			x++;
		} 
		l[i]=max(l[i-1],x-1);
//		cout<<l[i]<<' ';
	}
//	cout<<endl;
	for(int i=n-1;i>=1;i--)
	{
		int x=r[i+1];
		while(s[i+x-1]-s[i]<=k&&i+x<=n+1)
		{
			x++;
		}
		r[i]=max(r[i+1],x-1);
//		cout<<r[i]<<' '; 
	}
//	cout<<endl;
	for(int i=0;i<=n;i++)
	{
		ans=max(ans,l[i]+r[i+1]);
	}
	cout<<ans<<endl;
	
	return 0;
}

sequence

最难的一道DP.看了题解,还结合了另外的算法,于是先去把字符串哈希做了.

决定以后hash的mod就用1e9+7和1e7+7,base为131

#include <bits/stdc++.h>
#define ll long long

using namespace std;
const ll N=1e4+5,mod=1e9+7,base=131;
int n,ans;
ll a[N];
string s;

int main()
{	
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>s;
		int len=s.length();
		for(int j=0;j<len;j++)
		{
			a[i]=(a[i]*base+(ll)s[j])%mod;
		}
	}
	sort(a+1,a+n+1);
	for(int i=1;i<n;i++)
	{
		if(a[i]==a[i+1]) ans++;
	}
	cout<<n-ans;

	return 0;
}

回到这道题,我的思考过程落脚于将数列分开的"切点".切点前数列的长度一定小于等于切点后数列的长度.然后就开始愉快的正向DFS模拟了,每次可以将剩下没切的数列切下一块,但切的长度,要么是小于等于剩下长度的二分之一,要么是等于剩下的长度(切完).中途会比较本次切的部分与上次切的部分的大小.

一份代码就出炉了:

#include <bits/stdc++.h>

using namespace std;
const int N=5e3+5,mod=1e9+7;
int n,ans;
int s[N];

bool cmp(const int &l1,const int &r1,const int &l2,const int &r2)//if l1 to r1>l2 to r2
{
	if(r1-l1>r2-l2)
		return true;
	else if(r1-l1==r2-l2)
	{
		for(int i=l1;i<=r1;i++)
		{
			if(s[i]<s[l2+i-l1]) return false;
			if(s[i]==s[l2+i-l1]&&i==r1) return false;
		}
		return true;
	}
	else return false;
}

void solve(int l,int r,int pre_l,int pre_r)
{
	if(l==r)
	{
		(ans+=1)%=mod;
		return;
	}
	if(s[l]==0) return;
	int pre_size=pre_l-pre_r+1;
	for(int i=pre_size;i<=((r-l+1)/2);i++)
	{
		if(cmp(l,l+i-1,pre_l,pre_r))
			solve(l+i,r,l,l+i-1);
	}
	if(cmp(l,r,pre_l,pre_r))
	{
		solve(r,r,l,r);
	}
}

int main()
{
	freopen("sequence.in","r",stdin);
	freopen("sequence.out","w",stdout);
	
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%1d",&s[i]);
	}
	solve(1,n,0,0);
	cout<<ans%mod;
	
	return 0;
}

首先DFS不是正解DP,复杂度就被卡掉了,其次正确性还出了问题,另外,根本就没考虑到cmp函数会是正解程序优化的着重部分,复杂度Up.

如果复杂度过高,n=10的部分解也有30分,也是个不错的选择,但因为正确性问题,最终只得到了10分.

开始正解分析:

本题的答案需要mod 1e9+7,显然考虑DP求总方案数.定义f[i][j]为取[i,j]为最后一段的总方案数,那么f[i][j]可以由f[k][i-1]转移得到(k<i-1).

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值