本场链接:Codeforces Round #748 (Div. 3)
A. Elections
直接按题意模拟即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define forn(i,x,n) for(int i = x;i <= n;++i)
#define forr(i,x,n) for(int i = n;i >= x;--i)
#define OverJoy ios::sync_with_stdio(0),cin.tie(0);
#define x first
#define y second
int main()
{
int T;scanf("%d",&T);
while(T--)
{
int a,b,c;scanf("%d%d%d",&a,&b,&c);
if(max(b,c) >= a) printf("%d ",max(b,c) - a + 1);else printf("%d ",0);
if(max(a,c) >= b) printf("%d ",max(a,c) - b + 1);else printf("%d ",0);
if(max(a,b) >= c) printf("%d ",max(a,b) - c + 1);else printf("%d ",0);
puts("");
}
return 0;
}
B. Make it Divisible by 25
枚举一下25的倍数:25,50,75,100,125,150....可以发现 25 的倍数总是以 00 25 50 75 这四种结尾。直接枚举找出即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define forn(i,x,n) for(int i = x;i <= n;++i)
#define forr(i,x,n) for(int i = n;i >= x;--i)
#define OverJoy ios::sync_with_stdio(0),cin.tie(0);
#define x first
#define y second
const int N = 20;
const char* OP[] = {"00","25","50","75"};
char s[N];
int main()
{
int T;scanf("%d",&T);
while(T--)
{
scanf("%s",s + 1);int n = strlen(s + 1);
int res = 1e9;
forn(_,0,3)
{
forn(i,1,n)
{
if(s[i] != OP[_][0]) continue;
forn(j,i + 1,n) if(s[j] == OP[_][1]) res = min(res,n - i - 1);
}
}
printf("%d
",res);
}
return 0;
}
C. Save More Mice
可以想到:因为每次只能让一个老鼠动,所以最好的办法就是先找到最远的老鼠送过去,如此将所有老鼠的位置排序,每次看最后一个老鼠有没有被抓到,没有的话因为老鼠总先动,所以必然能把它送过去,再更新猫的位置继续即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define forn(i,x,n) for(int i = x;i <= n;++i)
#define forr(i,x,n) for(int i = n;i >= x;--i)
#define OverJoy ios::sync_with_stdio(0),cin.tie(0);
#define x first
#define y second
const int N = 4e5+7;
int a[N];
int main()
{
int T;scanf("%d",&T);
while(T--)
{
int n,k;scanf("%d%d",&n,&k);
forn(i,1,k) scanf("%d",&a[i]);
sort(a + 1,a + k + 1);
int cur = 0,res = 0;
forr(i,1,k)
{
if(a[i] > cur) ++res,cur += n - a[i];
else break;
}
printf("%d
",res);
}
return 0;
}
D1. All are Same
先考虑无解:当所有的数一开始就相同的时候无解,因为这些数怎么选 (k) 都可以。
其次,因为每个数都是去减若干倍的 (k) 所以对于一个可行的 (k),所有数关于 (k) 同余。枚举 (k) 的取值找到最大合适的数即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define forn(i,x,n) for(int i = x;i <= n;++i)
#define forr(i,x,n) for(int i = n;i >= x;--i)
#define OverJoy ios::sync_with_stdio(0),cin.tie(0);
#define x first
#define y second
const int N = 2e6+7;
int a[N];
int main()
{
int T;scanf("%d",&T);
while(T--)
{
int n;scanf("%d",&n);
forn(i,1,n) scanf("%d",&a[i]);
bool allsame = 1;
forn(i,1,n) if(a[i] != a[1]) allsame = 0;
if(allsame)
{
puts("-1");
continue;
}
int res = -1;
forn(k,1,2e6 + 1)
{
bool ok = 1;
int need = ((a[1] % k) + k) % k;
forn(i,1,n) if((a[i] % k + k) % k != need) ok = 0;
if(ok) res = max(res,k);
}
printf("%d
",res);
}
return 0;
}
D2. Half of Same
同理,如果一开始就有至少一半的数相同,那么无解。
由于 D1 做法的常数会因为 更多的修改 cnt 数组导致超时。考虑更本质的做法:假如说有解的话,那么必然会至少有一个数,在修改前盒修改后都没有变化,因为如果所有的数都减了 (k) 的若干倍,那么势必可以同时少减一次 (k) 使得操作数变得更少,与题目要求操作数最少矛盾。所以必然存在某个数,前后都没有变化。
那么枚举每个数 (a_j) 作为目标值,所有的数最后都会变成 (a_j) 枚举某个 (a_i) 令 (a_i - a_j) 作为 (k)(注意 (k geq 1))。而事实上,每个 (k) 的因数都是有可能的,所以直接把所有 (k) 的约数抠出来,最后找到最大且满足条件的 (k) 即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define forn(i,x,n) for(int i = x;i <= n;++i)
#define forr(i,x,n) for(int i = n;i >= x;--i)
#define OverJoy ios::sync_with_stdio(0),cin.tie(0);
#define x first
#define y second
const int N = 2e6+7;
int a[N],cnt[N];
int main()
{
int T;scanf("%d",&T);
while(T--)
{
int n;scanf("%d",&n);
forn(i,1,n) scanf("%d",&a[i]);
forn(i,1,n) ++cnt[a[i] + 1000000];
bool bad = 0;
forn(i,1,n) if(2 * cnt[a[i] + 1000000] >= n) bad = 1;
forn(i,1,n) --cnt[a[i] + 1000000];
if(bad)
{
puts("-1");
continue;
}
vector<int> st;
forn(i,1,n) forn(j,1,n) if(a[i] > a[j])
{
int k = a[i] - a[j];
for(int t = 1;t * t <= k;++t) if(k % t == 0) st.push_back(t),st.push_back(k / t);
}
int res = -1;
for(auto& k : st)
{
forn(i,1,n) ++cnt[(a[i] % k + k) % k];
bool ok = 0;
forn(i,1,n) if(2 * cnt[(a[i] % k + k) % k] >= n) ok = 1;
if(ok) res = max(res,k);
forn(i,1,n) --cnt[(a[i] % k + k) % k];
}
printf("%d
",res);
}
return 0;
}
E. Gardener and Tree
就是拓扑排序,把点的度数定义为与他相连的边的个数再按拓扑排序的方式逐层拆即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define forn(i,x,n) for(int i = x;i <= n;++i)
#define forr(i,x,n) for(int i = n;i >= x;--i)
#define OverJoy ios::sync_with_stdio(0),cin.tie(0);
#define x first
#define y second
const int N = 4e5+7;
vector<int> E[N];
int deg[N];
int main()
{
int T;scanf("%d",&T);
while(T--)
{
int n,k;scanf("%d%d",&n,&k);
forn(i,1,n) E[i].clear(),deg[i] = 0;
forn(i,2,n)
{
int u,v;scanf("%d%d",&u,&v);
E[u].push_back(v);E[v].push_back(u);
++deg[u];++deg[v];
}
int res = n,step = 0;
queue<int> q,t;forn(i,1,n) if(deg[i] == 1) q.push(i);
while(step < k)
{
if(res <= 2)
{
res = 0;
break;
}
res -= q.size();
while(!q.empty())
{
int u = q.front();q.pop();
for(auto& v : E[u]) if(--deg[v] == 1) t.push(v);
}
q = t;t = queue<int>();
++step;
}
printf("%d
",res);
}
return 0;
}