B. Send Boxes to Alice (Easy/Hard Version) (1s 256Mb)
题目大意
个排列好的盒子,每个盒子里有 块巧克力。可以花费1秒的时间将一块巧克力从一个盒子移动到左右相邻的盒子,问最少可以用多少秒,使得每个盒子里的巧克力数都可以被k整除。其中k是大于2的任意数。
分析
Easy:每个盒子要么有一块要么没有。对于specific k,将相邻的k个1整合所花费时间最少。可以暴力枚举所有sum(巧克力总数)的因数为k求解,取答案最小。小于1e5的数最多有128个因子。sum == 1时输出-1。O(128*n)。
Hard:
使用前缀和,移动等价于某个 加一或者减一。既然最后每个 可以被k整除(不同于Easy,可以是k的倍数),显然最终情况等价于每个 也可以被k整除。
对于每一个 ,使用 秒(贪心)使合法,由于 ,所以不会出现逆序的非法情况。可以O(n)求解一个k的答案。
观察可知答案对应的k一定是素数(合数k的情况被其素因子包括),对于1e12,最多有12个不同的素因子,唯一分解即可。
代码
const int maxn = 1e6+10;
int n;
ll a[maxn], s[maxn];
ll work(ll k)
{
ll res = 0;
for(int i = 1; i < n; i++) res += min(s[i]%k, k-s[i]%k);
return res;
}
int main()
{
n = read();
for(int i = 1; i <= n; i++) a[i] = read(), s[i] = s[i-1]+a[i];
if(s[n] == 1)
{
printf("-1\n"); return 0;
}
ll ans = 9e18, tmp = 2, num = s[n];
while(tmp * tmp <= num)
{
if(num%tmp == 0)
{
ans = min(ans, work(tmp));
while(num%tmp == 0) num /= tmp;
}
tmp++;
}
if(num > 1) ans = min(ans, work(num));
printf("%I64d\n", ans);
return 0;
}
C. League of Leesins (2s 256Mb)
题目大意
对于每个排列p有n-2 个q,。给出一组q,构造一个p。
分析
模拟题,找到只出现一次的p,一定是开头,找到含这个p的q里只出现两次的p,一定是开头后。使用这个q去递推下一个q,直到构成所有数列。
代码
const int maxn = 2e5+10;
struct Node
{
int fi, se, th;
} a[maxn];
vector<int> b[maxn];
int vis[maxn], visb[maxn], n, sum[maxn];
//cnt构建了几个 sta当前p第一个 fol第二个 nt第三个 id是q的下标
void dfs(int cnt, int sta, int fol, int nt, int id)
{
printf("%d ", nt); //输出
if(cnt == n-2) return;
vis[id] = 1; visb[nt] = 1;
int nid;//下一个q的id
if(cnt == 1) nid = b[fol][0] == id ? b[fol][1] : b[fol][0];// 第一个q无前一个q, 特判
else nid = vis[b[fol][0]] ? (vis[b[fol][1]] ? b[fol][2]:b[fol][1]):b[fol][0];//有nt的q里还没用过的
int nnt = visb[a[nid].fi] ? (visb[a[nid].se] ? a[nid].th : a[nid].se) : a[nid].fi;
dfs(cnt+1, fol, nt, nnt, nid);
}
int main()
{
n = read();
for(int i = 1, u, v, w; i <= n-2; i++)
{
u = read(), v = read(), w = read();
a[i] = (Node){u, v, w};
b[u].push_back(i);
b[v].push_back(i);
b[w].push_back(i);
sum[u]++, sum[v]++, sum[w]++;
}
int sta, fol, nt;
for(int i = 1; i <= n; i++) if(sum[i] == 1) { sta = i; break; }
if(sum[a[b[sta][0]].se] == 2)
{
fol = a[b[sta][0]].se;
if(sum[a[b[sta][0]].fi]== 3) nt = a[b[sta][0]].fi;
else nt = a[b[sta][0]].th;
}
else if(sum[a[b[sta][0]].fi] == 2)
{
fol = a[b[sta][0]].fi;
if(sum[a[b[sta][0]].se]== 3) nt = a[b[sta][0]].se;
else nt = a[b[sta][0]].th;
}
else if(sum[a[b[sta][0]].th] == 2)
{
fol = a[b[sta][0]].th;
if(sum[a[b[sta][0]].fi]== 3) nt = a[b[sta][0]].fi;
else nt = a[b[sta][0]].se;
}
printf("%d %d ", sta, fol);
visb[sta] = visb[fol] = 1;
dfs(1, sta, fol, nt, b[sta][0]);
return 0;
}
B. Fridge Lockers (1s 256Mb)
题目大意
花里胡哨。图,n个点,每个点有ai,要求建m条边,使得满足每个点都和至少两个不同的点相连,且代价最小。
分析
Mike翻车了hhh
https://codeforces.com/blog/entry/71562?#comment-559266