前言
《论如何搭讪异性》
- “同学,买保险吗?”
- “同学,这个香蕉皮是你吃剩下的吗?”
- “当我第一眼看到你的时候,我的脑海里就已经浮现出了我们离婚时的样子。”
A - Elections(思维)
比赛链接:https://codeforces.com/problemset/problem/1593/A
题目大意
有三人正在参加竞选。
现在竞选者 A A A获得了 a a a票,竞选者 B B B获得了 b b b票,竞选者 C C C获得了 c c c票。
只有当其中一个人的票数严格大于其他两人的票数时他才可以竞选成功。
现在请输出,三人如果想要竞选成功,每人至少要获得多少票。
思路
首先我们先算出三人之中最大票数 d d d。
- 如果三人之中只有一个人的票数为 d d d,则这个人不需要额外的票数就能竞选成功,而剩下的两个人需要达到 d + 1 d+1 d+1才可以竞选成功。
- 如果三人之中超过一人以上有 d d d票,则每个人都需要达到 d + 1 d+1 d+1票才能竞选成功。
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
ll a,b,c;
scanf("%lld%lld%lld",&a,&b,&c);
ll d=max(a,max(b,c));
int cnt=0;
cnt+=(d==a)?1:0;
cnt+=(d==b)?1:0;
cnt+=(d==c)?1:0;
///cout<<cnt<<endl;
if(cnt==1)
printf("%lld %lld %lld\n",(d==a)?0:(d-a+1),(d==b)?0:(d-b+1),(d==c)?0:(d-c+1));
else
printf("%lld %lld %lld\n",(d==a)?1:(d-a+1),(d==b)?1:(d-b+1),(d==c)?1:(d-c+1));
}
}
B - Make it Divisible by 25(暴力+模拟)
比赛链接:https://codeforces.com/problemset/problem/1593/B
题目大意
现在给你一个数字 n n n。
你可以删除其任意位置上的数使其变成一个新的数 n ′ n' n′, n ′ n' n′不能有前导 0 0 0。
例如, 10086 10086 10086在删掉第一位数字之后应该会变成 86 86 86,而不是 0086 0086 0086。
问:最少需要删掉多少位数字,才能使得 n ′ n' n′可以整除 25 25 25?
思路
遇到这种题,博主的建议是不要把 n n n当成数字来处理。
一个 1 e 18 1e18 1e18的数字固然可以用 l o n g long long l o n g long long来存储,但是我们也可以用 s t r i n g string string存储,这样的话删除某个数字的操作就变得额外简单了。
紧接着,我们都知道能够整除 25 25 25的数字,它的结尾为: 00 , 25 , 50 , 75 00,25,50,75 00,25,50,75。
所以依照这四个结尾组合对n进行删除操作,取最小的删除次数。
AC代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
string ss;
cin>>ss;
int len=ss.size();
int cnt1=0,cnt2=0;
for(int i=len-1;i>=0;i--){
if(ss[i]!='5') cnt1++;
else{
for(int j=i-1;j>=0;j--,cnt1++){
if(ss[j]=='2'||ss[j]=='7')
break;
}
break;
}
}
for(int i=len-1;i>=0;i--){
if(ss[i]!='0') cnt2++;
else{
for(int j=i-1;j>=0;j--,cnt2++){
if(ss[j]=='5'||ss[j]=='0')
break;
}
break;
}
}
cout<<min(cnt1,cnt2)<<endl;
}
}
C - Save More Mice(贪心)
比赛链接:https://codeforces.com/problemset/problem/1593/C
题目大意
J e r r y Jerry Jerry邀请了它的老鼠朋友们来到女主人的家里开派对, T o m Tom Tom发现之后并没有阻止,它躲在冰箱后伺机而动。
终于,有 k k k只老鼠喝醉了,在了地板上打起了滚, T o m Tom Tom出击,老鼠们看到在冰箱后的汤姆之后开始逃窜。
T o m Tom Tom处于 x = 0 x=0 x=0的位置,第 i i i只老鼠处于 x i x_i xi的位置,而老鼠洞处于 x = n x=n x=n的位置。
每一秒的开始阶段,你可以选择 1 1 1只老鼠向右移动一格。
当这一秒结束时, T o m Tom Tom会向右移动一格,并抓走它所在位置上的所有老鼠。
老鼠们到达老鼠洞时就会安全。
现在 J e r r y Jerry Jerry在客厅观看它老舅的表演,并没有注意到厨房发生了什么。
请问,你最多可以让几只老鼠进洞,不被 T o m Tom Tom抓走?
思路
我们计算出每只老鼠离老鼠洞还有多远距离,优先让离洞的近的老鼠逃进洞里。
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=4e5+100;
struct node
{
int x,tanx;
}a[maxn];
bool cmp(node z,node c){
return z.tanx<c.tanx;
}
int main()
{
int t;
cin>>t;
while(t--){
ll n;
int k;
cin>>n>>k;
for(int i=0;i<k;i++)
{
cin>>a[i].x;
a[i].tanx=n-a[i].x;
}
sort(a,a+k,cmp);
ll sum=0; //Tom的位置
int pos=-1;
for(int i=0;i<k;i++)
{
if(sum>=a[i].x){
pos=i;
break;
}
sum+=a[i].tanx;
}
if(pos==-1) pos=k;
cout<<pos<<endl;
}
}
D1. All are Same(思维+最大公约数)
比赛链接:https://codeforces.com/contest/1593/problem/D1
题目大意
现在给出 n n n个数字,找到一个最大的 k ( k > = 1 ) k(k>=1) k(k>=1),使得每个数可以在加/减若干个 k k k之后值相等。
若 k k k可以无限大,则输出 − 1 -1 −1。
思路
首先先考虑 k k k可以无限大的情况: n n n个数字全部相等。
博主因为没考虑这一点,第一发 W A WA WA在第 6 6 6个测试点了。
接下来考虑 k k k存在切实值的情况。
我们先给数组进行排序(从小到大),博主的想法是让所有的数都变成最大的数。
此时我们随机选中两个数 a [ i ] a[i] a[i]与 a [ j ] a[j] a[j],则有:
a [ i ] + x ∗ k = = a [ n ] a[i]+x*k==a[n] a[i]+x∗k==a[n]
a [ j ] + y ∗ k = = a [ n ] a[j]+y*k==a[n] a[j]+y∗k==a[n]
可以看出, k k k是 a [ n ] − a [ i ] a[n]-a[i] a[n]−a[i]与 a [ n ] − a [ j ] a[n]-a[j] a[n]−a[j]的最大公约数。
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=4e5+100;
int a[50];
int main()
{
ios::sync_with_stdio(false);
int t;
cin>>t;
while(t--)
{
int n,x;
cin>>n;
set<int> s;
for(int i=1; i<=n; i++)
{
cin>>a[i];
s.insert(a[i]);
}
sort(a+1,a+1+n);
if(a[1]==a[n]) cout<<"-1"<<endl;
else
{
int gcd=a[n]-a[1];
for(int i=2;; i++)
{
if(a[n]-a[i]==0) break;
gcd=__gcd(gcd,a[n]-a[i]);
}
cout<<gcd<<endl;
}
}
}
D2. Half of Same(暴力+最大公约数)
比赛链接:https://codeforces.com/contest/1593/problem/D2
题目大意
现在给出 n n n个数字,找到一个最大的 k ( k > = 1 ) k(k>=1) k(k>=1),使得有至少 n / 2 n/2 n/2个数可以在加/减若干个 k k k之后值相等。
若 k k k可以无限大,则输出 − 1 -1 −1。
思路
还是先找出 k k k可以无限大的情况:至少有 n / 2 n/2 n/2个数字全部相等。
接下来,由于这个 n n n的范围实在是太小了( n < = 40 n<=40 n<=40),所以我们干脆直接暴力处理,找到所有可能的 k k k。
sort(a+1,a+1+n);
set<int> s1,s2; //s1:存储所有数之间的差值 s2:存储所有可能的k值
for(int i=1; i<=n; i++)
for(int j=i+1; j<=n; j++)
s1.insert(a[j]-a[i]);
for(auto i:s1)
for(auto j:s1)
s2.insert(__gcd(j,i));
用每一个 k k k去试,只要可以达成条件则进行记录,最后输出最大的 k k k值。
O ( n 3 ) O(n^3) O(n3)的算法,但是 n n n的值太小了。
AC代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=4e5+100;
int a[50];
int main()
{
ios::sync_with_stdio(false);
int t;
cin>>t;
while(t--)
{
int n,x;
int flag=0;
cin>>n;
map<int,int> mp;
for(int i=1; i<=n; i++)
{
cin>>a[i];
mp[a[i]]++;
if(mp[a[i]]>=n/2) flag=1;
}
if(flag) cout<<"-1"<<endl;
else
{
sort(a+1,a+1+n);
set<int> s1,s2;
for(int i=1; i<=n; i++)
for(int j=i+1; j<=n; j++)
s1.insert(a[j]-a[i]);
for(auto i:s1)
for(auto j:s1)
s2.insert(__gcd(j,i));
int k=-1;
for(auto i:s2)
{
if(!i) continue;
for(int c=1; c<=n; c++)
{
int cnt=0;
for(int d=1; d<=n; d++)
if(abs(a[d]-a[c])%i==0) cnt++;
if(cnt>=n/2) k=max(k,i);
}
}
cout<<k<<endl;
}
}
}
后话
感谢阅读,希望能对你产生一点用处。
终于追完权游了。真的没想到Tyrion会成为最后的兰尼斯特,爱了。
(下图为决战前一晚,兰尼斯特兄弟最后的拥抱)