TopCoder SRM 574

div.1

T1

题意

有两个数字a,b
玩家A 持有a,玩家B 持有b
他们可以改变自己的数字 方式为

  1. 倒转
    2.除以10
    两人轮流进行操作 A先
    若在1000步以内可以使得两个数字相同 则A胜利 反之 A失败

思路

只要判断一下 a中有没有b或b的翻转数的子串 即可

//tc is healthy, just do it
#include 
using namespace std;

class TheNumberGame {
public:
    string determineOutcome( int A, int B );
};
inline int sol(int x)
{
	int s=0;
	while(x>0)
	{
		s=s*10+(x%10);
		x=x/10;
	}
	return s;
}
string TheNumberGame::determineOutcome(int a, int b) {
    int i,n;
    for(n=1;n<=b;n*=10);
    cout<<n<<" ";
    for(i=a;i;i/=10)
    	if(i%n==b) return "Manao wins";
    b=sol(b);
    for(i=a;i;i/=10)
    	if(i%n==b) return "Manao wins";
    return "Manao loses";
}

T2

题意

一个正N边形,按给出的顺序连起M个点,然后你按照顺序连起剩下的N-M个点。要求每次新连的线段必须与前面的线段相交。求全部连完回到起始点的方案数。

思路

定义dp[i][j]表示此时在i,取得点的集合为j。
发现,如果x想要到y,那么在圆上x顺时针到y或x逆时针到y一定都要有点。

#include 
using namespace std;
int n,m,vis[10010],tot;
long long d[18][1<<18];
vector<int> a;
class PolygonTraversal {
public:
    long long count( int N, vector <int> points );
};
int work(int now,int to,int s)
{
	int temp,l=0,r=0;
	temp=(to+1)%n;
	while(temp!=now)
		if(vis[temp]||s&(1<<temp))
		{
			l=1;
			break;
		}
		else temp=(temp+1)%n;
	temp=(now+1)%n;
	while(temp!=to)
		if(vis[temp]||s&(1<<temp))
		{
			r=1;
			break;
		}
		else temp=(temp+1)%n;
	if(l&&r) return 1;
	return 0;
}
long long sol(int p,int s,int cnt)
{
	long long &ans=d[p][s];
	if(ans) return ans;
	if(cnt==n) 
	{
		ans=work(p,a[0],s);
		return ans;
	}
	ans=0;
	for(int i=0;i<n;i++)
	{
		if(i==p||vis[i]||(s&(1<<i))) continue;
		if(work(p,i,s)) ans+=sol(i,s|(1<<i),cnt+1);
	}
	return ans;
}
long long PolygonTraversal::count(int N, vector <int> A) {
	int i;
	n=N;
	a=A;
	m=a.size();
	memset(vis,0,sizeof(vis));
	tot=0;
	for(i=0;i<m;i++) a[i]--,vis[a[i]]=1,tot+=(1<<a[i]);
	return sol(a[m-1],tot,m);
}

div.2

T3

此题与div.1的T2 相同 只是 数据范围更小了

参考上面即可

你可能感兴趣的:(TopCoder,题解)