Codeforces Round #519 by Botan Investments
A. Elections
#include <bits/stdc++.h>
using namespace std;
int n, mx = 0, sum = 0, x;
int main() {
scanf("%d",&n);
for(int i = 1; i <= n; ++i)
scanf("%d",&x), sum += x, mx = max(mx, x);
int k;
for(k = mx; k <= 500; ++k) {
if(k*n > (sum<<1)) {
printf("%d\n",k); return 0;
}
}
return 0;
}
B. Lost Array
做法:枚举k判断合法性,根据前k+1个a,求出x,再进行判断即可。
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int n, cnt, b[1111];
ll a[1111], x[1111];
int ck(int k) {
for(int i = 0; i < k; ++i) x[i] = a[i+1] - a[i];
ll b = 0;
for(int i = 1; i <= n; ++i) {
b = b + x[(i-1)%k];
if(b != a[i]) return 0;
}
return 1;
}
int main() {
scanf("%d",&n);
for(int i = 1; i <= n; ++i) scanf("%lld",&a[i]);
for(int k = 1; k <= n; ++k) {
if(ck(k)) b[++cnt] = k;
}
printf("%d\n",cnt);
for(int i = 1; i<= cnt; ++i) printf("%d ",b[i]); puts("");
return 0;
}
C. Smallest Word
做法:从前到和维护一个前i个字符能构成字典序最小的串,然后对于第i个串,需要考虑前i-1个字符形成的串,以及加入第i个字符后是否反转,转移即可。
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int n, ans[1111];
char str[1111];
bool operator < (const string a, const string b) {
for(int i = 0; i < a.size(); ++i) if(a[i] != b[i]) return a[i] < b[i];
return 1;
}
string cal(string s) {
string t = s;
reverse(t.begin(), t.end());
return min(t,s);
}
int main() {
scanf("%s", str+1); n = strlen(str+1);
string s, t1, t2, t11, t22; s += str[1];
for(int i = 2; i <= n; ++i) {
t1 = t2 = s;
t1 += str[i];
reverse(t2.begin(), t2.end()); t2 += str[i];
t11 = t1; reverse(t11.begin(), t11.end());
t22 = t2; reverse(t22.begin(), t22.end());
s = min(min(t1,t2), min(t11, t22));
if(s == t1) continue;
else if(s == t2) ans[i-1]^=1;
else if(s == t11) ans[i]^=1;
else ans[i-1]^=1, ans[i]^=1;
}
for(int i = 1; i <= n; ++i) printf("%d ",ans[i]); puts("");
return 0;
}
D. Mysterious Crime
做法:贪心的满足第一个串,然后根据第一个串判断所有的串最长匹配到什么位置,匹配失败后,就将这段区间的数字的答案计算完成了。然后,继续枚举下一段即可,这样已经计算的数字一定是最优的。
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int n, m, b[100007], pos[12][100007], p[12], a[12][100007];
bool ck() {
if(b[a[1][p[1]]]) return 0;
if(p[1] > n) return 0;
for(int i = 2; i <= m; ++i) {
if(p[i] > n || a[i][p[i]] != a[i-1][p[i-1]] || b[a[i][p[i]]]) return 0;
}
return 1;
}
void cal(int x) {
int ans = 0;
for(int i = 1; i <= m; ++i) p[i] = pos[i][x];
while(ck()) {
for(int i = 1; i <= m; ++i) ++p[i];
++ans;
}
for(int j = pos[1][x], t = ans; t ; ++j, --t) b[a[1][j]] = t;
return;
}
int main() {
scanf("%d%d",&n,&m);
for(int i = 1; i <= m; ++i)
for(int j= 1; j <= n; ++j) {
scanf("%d",&a[i][j]);
pos[i][a[i][j]] = j;
}
for(int i = 1; i <= n; ++i) if(!b[a[1][i]]) {
cal(a[1][i]);
}
ll ans = 0;
for(int j = 1;j <= n; ++j) ans += 1LL*b[j];
printf("%lld\n",ans);
return 0;
}
/*
4 2
1 2 4 3
4 3 1 2
*/
E. Train Hard, Win Easy
做法:求\[\sum _{i=1}^n \sum_{j=1,j != i,can[i][j] = 0} ^n min(a[i].x+a[j].y, a[i].y+a[j].x)\]
首先 i,j 之间不能计算的答案可以从最终的答案中减去,那么考虑如何优化掉第二维;min提醒我们可以讨论。当\(a[i].x + a[j].y <= a[i].y + a[j].x\) 即\(a[i].x - a[i].y <= a[j].x - a[j].y\)时最小值是\(a[i].x + a[j].y\)
排序之后分别考虑贡献即可;另一种情况,同理。可以通过预处理解决。
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i = (a); i <= (b); ++i)
#define per(i,a,b) for(int i = (a); i >= (b); --i)
typedef long long ll;
using namespace std;
int n, m, x, y;
struct node{
ll x, y; int id;
bool operator < (const node &a) const { return x - y < a.x - a.y; }
}a[300007];
ll ans[300007], sx[300007], sy[300007];
int main() {
scanf("%d%d",&n,&m);
rep(i,1,n) scanf("%lld%lld", &a[i].x, &a[i].y), a[i].id = i;
rep(i,1,m) {
scanf("%d%d", &x, &y);
ans[x] -= min(a[x].x+a[y].y, a[x].y+a[y].x);
ans[y] -= min(a[x].x+a[y].y, a[x].y+a[y].x);
} sort(a+1, a+1+n);
per(i,n,1) sy[i] = sy[i+1] + a[i].y; rep(i,1,n) sx[i] = sx[i-1] + a[i].x;
for(int num, i = 1; i <= n; ++i) {
num = lower_bound(a+1,a+1+n,a[i])-a-1;
ans[a[i].id] += a[i].x*(n - num - 1LL) + sy[num+1] - a[i].y + a[i].y*num + sx[num];
}
for(int i = 1; i<= n; ++i) printf("%lld ", ans[i]); puts("");
}
F. Make It One
做法:求至少挑多少个数可以使得他们的gcd为1。首先,可以证明最多挑7个数,因为这些数两两之间至少有一个不重复的公共素数。\(dp[i][j]\) 表示选 i 个数gcd为 j 的方案数,那么通过容斥转移就是
\[dp[i][j] = C_{num_j}^i - \sum_{k=2}^\infty dp[i][j*k] \]
\[num_j = \sum_{i=1}^n [a[i] ~mod ~j = 0]\]
即从包含j的数里挑i个的方案数,去掉包含\(j\)的倍数的方案数,这个值可能很大运算过程中取模即可。答案就是找到最小的\(i\)使得\(dp[i][1]>0\)
#include <bits/stdc++.h>
typedef long long ll;
const int N = 3e5 + 7;
const int mod = 1e9 + 7;
using namespace std;
int num[N], a[N], n, MX;
ll dp[11][N], f[N], inv[N];
ll q_pow(ll a, ll b) {
ll ans = 1;
while(b) {
if(b&1) ans = (ans*a) % mod;
a = (a*a) % mod;
b >>= 1LL;
}
return ans;
}
void init() {
f[0] = 1;
for(int i = 1; i <= 3e5; ++i) f[i] = (f[i-1]*i) % mod;
inv[300000] = q_pow(f[300000], mod-2);
for(int i = 300000-1; i >= 0; --i) inv[i] = (inv[i+1]*(i+1LL)) % mod;
}
ll C(int n, int m) {
if(m > n) return 0;
if(m == n || !m ) return 1;
return (f[n]*inv[m])%mod*inv[n-m]%mod;
}
void solve(int x) {
for(int i = 1; i*i <= x; ++i) if(x % i == 0) {
++num[i];
if(i*i == x) continue;
++num[x/i];
}
}
int main() {
init();
scanf("%d",&n);
for(int i = 1; i <= n; ++i)
scanf("%d", &a[i]), solve(a[i]), MX = max(MX,a[i]);
for(int i = 1; i <= 7; ++i) {
for(int j = MX; j >= 1; --j) {
dp[i][j] = C(num[j],i);
for(int k = j+j; k <= MX; k += j) {
dp[i][j] -= dp[i][k];
if(dp[i][j] < 0) dp[i][j]+=mod;
dp[i][j] %= mod;
}
}
if(dp[i][1] > 0) {
printf("%d\n",i); return 0;
}
}
puts("-1");
return 0;
}
G. Speckled Band
做法:略猛,有缘再写了。。。