Codeforces Round #574 (Div. 2)
这套题目比较简单,然而我才 (A) 了 (4) 道题目,而且其中的一道题目赛后还调了很长时间。
A. Drinks Choosing
这道题目的困难在读题,读了 (20) 多分钟的题目还没读懂,后来去 (luogu) 看的翻译,直接贪心就可以了,先把可以凑成两个的填完,然后剩下的填 (1) 个的就可以了。
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+100;
int n,k;
int tp[N];
int main()
{
scanf("%d%d",&n,&k);
for (int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
tp[x]++;
}
int mid=n/2;
if (n%2==1) mid++;
for (int i=1;i<=k;i++)
if (tp[i]&&mid-tp[i]/2>=0)
{
mid-=tp[i]/2;
tp[i]%=2;
}
for (int i=1;i<=k;i++)
if (tp[i]&&mid-1>=0)
{
tp[i]=0;
mid--;
}
int sum=0;
for (int i=1;i<=k;i++)
sum+=tp[i];
printf("%d
",n-sum);
return 0;
}
B. Sport Mafia
这道题直接枚举就可以了,看似是 (Theta (n)) 的复杂度,其实根据等差数列求和公式 (n*(n+1)/2) ,所以最坏时间复杂度是 (Theta (sqrt{n})) ,然后就可以过了。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n,k;
int main()
{
scanf("%lld%lld",&n,&k);
for (ll i=1;i<=n;i++)
if (i*(i+1)/2-n+i==k)
{
printf("%lld
",n-i);
return 0;
}
return 0;
}
C. Basketball Exercise
这道题目是一个比较简单的 (DP) ,转移只有三种情况,从上一列的不同颜色转移过来,从上上一列的两种颜色转移过来。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+100;
ll a[N][4],f[N][4];
int n;
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%lld",a[i]+1);
for (int i=1;i<=n;i++)
scanf("%lld",a[i]+2);
f[1][1]=a[1][1];
f[1][2]=a[1][2];
for (int i=2;i<=n;i++)
{
f[i][1]=f[i-1][2]+a[i][1];
f[i][2]=f[i-1][1]+a[i][2];
if (i>=3)
{
f[i][1]=max(max(f[i-2][1],f[i-2][2])+a[i][1],f[i][1]);
f[i][2]=max(max(f[i-2][1],f[i-2][2])+a[i][2],f[i][2]);
}
}
printf("%lld
",max(f[n][1],f[n][2]));
return 0;
}
D. Submarine in the Rybinsk Sea
这题的简单版比较简单,直接按照每一位算贡献就可以了,每一个数第 (i) 位 (x) 的贡献就是
[x*10^{i*2}*n+x*10^{i*2-1}*n
]
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+100,MOD=998244353;
int n;
ll a[N];
ll ans;
inline void work(ll x)
{
int num=0;
while (x)
{
ll will=pow(10,num*2);
ans=(ans+((x%10)*will%MOD+((x%10)*will%MOD*10%MOD))*n%MOD)%MOD;
x=x/10;
++num;
}
return ;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%lld",a+i);
for (int i=1;i<=n;i++)
work(a[i]);
printf("%lld",ans);
return 0;
}
困难版其实只需要修改一下就可以了,当一个数第 (i) 位有 (x*10^{i*2}) 和 (x*10^{i*2-1}) 时必须和这个数相同的位数或者大于这个数数位的数一起做 (f) 操作。
E. OpenStreetMap
这道题直接跑滑动窗口就可以了,每一行跑一遍,然后再在列上跑一遍就可以了。
#include<bits/stdc++.h>
#define ll long long
const int N=3e3+100;
using std::vector;
ll n,m,a,b,ans;
ll x,y,z;
ll g[N*N],h[N][N],minn[N][N];
vector<ll>v;
int main()
{
scanf("%lld%lld%lld%lld",&n,&m,&a,&b);
scanf("%lld%lld%lld%lld",&g[0],&x,&y,&z);
for (int i=1;i<=N*N-100;i++)
g[i]=(g[i-1]*x+y)%z;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
h[i][j]=g[(i-1)*m+j-1];
for (int i=1;i<=n;i++)
{
v.clear();
for (int j=1;j<=m;j++)
{
while (!v.empty()&&h[i][v.back()]>h[i][j]) v.pop_back();
v.push_back(j);
if (!v.empty()&&v.front()<j-b+1) v.erase(v.begin(),v.begin()+1);
if (j>=b) minn[j][i]=h[i][v.front()];
}
}
for (int i=b;i<=m;i++)
{
v.clear();
for (int j=1;j<=n;j++)
{
while (!v.empty()&&minn[i][v.back()]>minn[i][j]) v.pop_back();
v.push_back(j);
if (!v.empty()&&v.front()<j-a+1) v.erase(v.begin(),v.begin()+1);
if (j>=a) ans+=minn[i][v.front()];
}
}
printf("%lld
",ans);
return 0;
}