题号
A - Alice and Bob
博弈。
A和B从两堆石头中轮流取石头,规则是每次可以从其中一堆中取出k个(k>=1),同时从另一堆石头中取出s*k个(s>=0),无石头可取时输。
显然必败态的所有前置都是必胜态,必胜态的所有前置中至少有一个必败态。
同时可以得到推论:设第一堆石头有i个,第二堆石头有j个,对于每一个i,至多有一个j与其对应,使状态(i,j)为必败态。(i,j>=1)
打表即可。
Ac代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 5000;
bool lst[N+1][N+1];
void printlist()
{
for(int i = 0 ; i <= N ; i ++)
for(int j = 0 ; j <= N ; j ++)
if (!lst[i][j]&&!lst[j][i])
{
for(int k = 1 ; i + k <= N ; k ++)
for(int s = 0 ; j + s * k <= N ; s ++)
lst[i+k][j+s*k] = 1;
for(int k = 1 ; j + k <= N ; k ++)
for(int s = 0 ; i + s * k <= N ; s ++)
lst[i+s*k][j+k] = 1;
break;
}
}
int main (void)
{
printlist();
int t;
cin >> t;
while (t--)
{
int n , m;
scanf("%d %d",&n,&m);
if (lst[n][m])
cout << "Alice";
else
cout << "Bob";
cout << endl;
}
return 0;
}
B - Ball Dropping
简单几何。
#include <bits/stdc++.h>
using namespace std;
int main (void)
{
double r , a , b , h;
cin >> r >> b >> a >> h;
int flag = 0;
if (2 * r < a)
{
cout << "Drop" << endl;
}
else
{
double l = a * h / (b - a);
double q = 2 * h * r / (b - a);
double ll = sqrt(r * r + q * q);
double ans = ll - l;
cout << "Stuck" << endl;
printf ("%.6lf\n",ans);
}
return 0;
}
D - Determine the Photo Position
签到题。
#include <bits/stdc++.h>
using namespace std;
int n , m;
string s;
int main (void)
{
int cnt = 0,fg = 0;
cin >> n >> m;
for(int i = 0 ; i < n ; i ++)
{
fg = 0;
cin >> s;
for(int j = 0 ; j <= s.size() ; j ++)
{
if (s[j] == '0')
{
fg ++;
if (fg >= m)
cnt ++;
}
else
fg = 0;
}
}
cin >> s;
cout << cnt << endl;
return 0;
}
F - Find 3-friendly Integers
我们称一个数是3的友好数,当这个数中某些连续的位组成的数能够被3整除。如101是3的友好数,因为它的十位数0被3整除。问区间[l,r]间有多少3的友好数。
首先应该知道一个常见结论:如果一个数每一位数字相加被3整除,那么这么数就被3整除。
因此要判断某个数是不是3的友好数,就要看它的某些连续位之和能不能被3整除。因此根据同余定理,可以先对这个数的每一位对3取余,这时候每一位可能出现的数字无非0,1,2。
这时候能够发现:大于等于100的数不可能出现非3友好数。证明这个推论,我们可以从递推的角度。某个个位数是非3友好数,那么取模之后它只能是1或2。如果某个十位数是非3友好数,那么它首先应该满足每一位都是非3友好数,即从个位非3友好数递推而来,此外十位与个位之和不能为3的倍数,那么在取模意义下只有11和22满足条件。再看百位数,此时我们发现不论在11或22的哪一位插入1或者2都是无法构造出非3友好数的。
知道结论,打表记录每个数之前有多少个非3友好数即可,并且只用打到99即可。
Ac代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100;
ll lst[N];
int check(int n)
{
if (n < 10 && (n%3==1||n%3==2))
return 1;
if (n > 10 && ((n%10%3==1&&n/10%3==1)||(n%10%3==2&&n/10%3==2)))
return 1;
return 0;
}
void printlist()
{
for(int i = 1 ; i < N ; i ++)
{
lst[i] = lst[i-1] + check(i);
}
}
int main (void)
{
printlist();
int t;
cin >> t;
while (t--)
{
ll l , r , ans;
cin >> l >> r;
if (l >= 100)
ans = r - l + 1;
if (l < 100)
{
if (r >= 100)
ans = r - l + 1 - (lst[99] - lst[l-1]);
else
ans = r - l + 1 - (lst[r] - lst[l-1]);
}
cout << ans << endl;
}
return 0;
}
G - Game of Swapping Numbers
给定两个长度为n的序列a、b,进行k次操作,每次可以选择ai与aj交换位置(i<j),求max∑|a[i]-a[j]|.
碰见绝对值符号应当首先考虑去除绝对值符号。为达到去除绝对值符号的目的,必须将a与b中每个数都标上正负号,目标求和即可转化为a,b中所有数的和。
此时考虑交换操作,交换操作可以视为交换a,b中任意两个数的符号。显然最优解是不断的将负值中数字最大的数与正值中数字最小的数交换,最优解即正值中数字最小的值大于负值中数字最大的值。
n>2时,确实进行k次操作的最优解与最多进行k次操作的最优解等价。达到最优解后仍有多余的操作数可以通过交换相同符号的数消耗。
Ac代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 7;
int a[N] , b[N];
priority_queue<int,vector<int>,greater<int>> hz;
priority_queue<int,vector<int>> hf;
int main (void)
{
int n , k;
cin >> n >> k;
for(int i = 0 ; i < n ; i ++)
cin >> a[i];
for(int i = 0 ; i < n ; i ++)
cin >> b[i];
for(int i = 0 ; i < n ; i ++)
{
if (a[i] >= b[i])
{
hz.push(a[i]);
hf.push(b[i]);
}
else
{
hz.push(b[i]);
hf.push(a[i]);
}
}
long long ans = 0;
if (n == 2)
{
k %= 2;
if (k)
swap(a[0],a[1]);
ans = abs(a[0]-b[0]) + abs(a[1]-b[1]);
}
else
{
while (hz.top() < hf.top() && k)
{
int tz = hz.top() , tf = hf.top();
hz.pop();
hf.pop();
hf.push(tz);
hz.push(tf);
k--;
}
while (hz.size())
{
ans += hz.top();
ans -= hf.top();
hz.pop();
hf.pop();
}
}
cout << ans << endl;
return 0;
}
K - Knowledge Test about Match
非常玄学的一道题,不知道该说什么好。
Ac代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
int a[N] , b[N];
double cal(int a , int b)
{
return sqrt(abs(a-b));
}
int main (void)
{
int t;
cin >> t;
while (t--)
{
int n;
scanf("%d",&n);
for(int i = 0; i < n; i ++)
{
scanf("%d",&b[i]);
}
int m = 4;
while (m--)
for(int i = 0 ; i < n ; i ++)
{
for(int j = i+1 ; j < n ; j ++)
{
if (cal(i,b[i]) + cal(j,b[j]) > cal(i,b[j]) + cal(j,b[i]))
swap(b[i],b[j]);
}
}
for(int i = 0 ; i < n ; i ++)
{
printf ("%d ",b[i]);
}
cout << endl;
}
return 0;
}