div.1
T1
题意
有两个数字a,b
玩家A 持有a,玩家B 持有b
他们可以改变自己的数字 方式为
- 倒转
2.除以10
两人轮流进行操作 A先
若在1000步以内可以使得两个数字相同 则A胜利 反之 A失败
思路
只要判断一下 a中有没有b或b的翻转数的子串 即可
//tc is healthy, just do it
#include <bits/stdc++.h>
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 <bits/stdc++.h>
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 相同 只是 数据范围更小了
参考上面即可