Codeforces Round #677 (Div. 3) A-E
模拟
#include <iostream>
using namespace std;
int main()
{
//freopen("data.txt", "r", stdin);
int t;
cin >> t;
while(t--)
{
int x;
cin >> x;
int len = 0, num = x % 10;
while(x)
{
len++;
x /= 10;
}
cout << (num - 1) * 10 + (len == 1 ? 1 : (1 + len) * len / 2) << endl;
}
return 0;
}
大意是给一个01序列,每次可以选择其中l到r的一段往左或者右平移一格(前提是那个位置为0),问最少多少次能让所有的1均相邻。
显然答案是第一个1到最后一个1之间的0的个数。
#include <iostream>
using namespace std;
int n, a[55];
int main()
{
//freopen("data.txt", "r", stdin);
int t;
cin >> t;
while(t--)
{
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
int ans = 0;
int last = 0;
for(int i = 1; i <= n; i++)
{
if(last)
{
if(a[i])
{
ans += i - last - 1;
last = i;
}
}
else
{
if(a[i]) last = i;
}
}
cout << ans << endl;
}
return 0;
}
大意是有n条鱼,每条鱼有一个size,一条鱼可以吃掉相邻的且size小于它的鱼同时自己的size会加一,最后剩下的是鱼王,输出鱼王的编号(没有的话输出-1)。
容易知道序列仅有一种数时无解,否则一定有解。因为是随意输出,因此可以扫一遍序列找到最大的size,然后从所有size为最大size的鱼里面挑一条能吃掉相邻鱼的即可,因为只要它一开始能吃掉相邻的鱼,它的size就严格大于其他任意鱼了。
#include <iostream>
using namespace std;
int n, a[300005];
int main()
{
//freopen("data.txt", "r", stdin);
int t;
cin >> t;
while(t--)
{
cin >> n;
a[0] = 0x3f3f3f3f, a[n + 1] = 0x3f3f3f3f;
for(int i =1; i <= n; i++) cin >> a[i];
int mmax = 0;
for(int i = 1; i <= n; i++)
{
mmax = max(mmax, a[i]);
}
int cnt = 0, pos = 0;
for(int i = 1; i <= n; i++)
{
if(a[i] == mmax)
{
cnt++;
if(a[i] > a[i - 1] || a[i] > a[i + 1]) pos = i;
}
}
if(cnt == n) cout << -1 << endl;
else cout << pos << endl;
}
return 0;
}
大意是给n个点,每个点有一个值,求一个连接n个点的树,并且连边的两个点之间的值不同。
由于点只有5e3个,直接\(O(n^2)\)扫一遍,把值不同的两个点之间建边扔进vector,然后执行类似kruskal的过程即可(并查集的fa数组记得每次初始化)。
#include <iostream>
#include <vector>
using namespace std;
int n, a[5005];
int fa[5005];
int get(int x)
{
if(x == fa[x]) return x;
return fa[x] = get(fa[x]);
}
struct edge
{
int x, y;
};
int main()
{
//freopen("data.txt","r", stdin);
int t;
cin >> t;
while(t--)
{
cin >> n;
vector<edge> v;
for(int i = 1; i <= n; i++)
{
cin >> a[i];
fa[i] = i;
}
for(int i = 1; i <= n; i++)
{
for(int j = i + 1; j <= n; j++)
{
if(a[i] != a[j]) v.push_back(edge{i, j});
}
}
int cnt = 0;
vector<edge> ans;
for(int i = 0; i < v.size(); i++)
{
if(cnt == n - 1)break;
int xx = get(v[i].x), yy = get(v[i].y);
if(xx == yy) continue;
fa[xx] = yy;
cnt++;
ans.push_back(v[i]);
}
if(cnt == n - 1)
{
cout << "YES" << endl;
for(int i = 0; i < ans.size(); i++)
{
cout << ans[i].x << ' ' << ans[i].y << endl;
}
}
else cout << "NO" << endl;
}
return 0;
}
把1到n这n个数分成两组,问有多少种分法,其中1 4 2 3和4 2 3 1这样的算一种。
排列组合题,首先挑出来一组,是\(C^{\frac{2}{n}}_n\),这样的话其实两个组的数都能确定下来了,然后是顺序问题,对于每一组,首先是求全排列,但这样还无法排除掉循环的情况(如1 4 2 3和4 2 3 1),因此要除以每组的长度\(\frac{2}{n}\),最后别忘除以2(因为第一组1 4 2 3 第二组5 6 8 7和第二组1 4 2 3 第一组5 6 8 7在题目里算一种)
#include <iostream>
using namespace std;
long long C(int n, int m)
{
if (m < n - m) m = n - m;
long long ans = 1;
for (int i = m + 1; i <= n; i++) ans *= i;
for (int i = 1; i <= n - m; i++) ans /= i;
return ans;
}
long long f(int n)
{
long long ans = 1;
for(int i = 1; i <= n; i++) ans = ans * (1ll * i);
return ans;
}
int main()
{
//freopen("data.txt", "r", stdin);
int n;
cin >> n;
cout << C(n, n / 2) * f(n / 2) * f(n / 2) / (n / 2) / (n / 2) / 2;
return 0;
}