爪哇周赛 Round 3
A
题目:oj | 回声频段
思路:
题目保证凡是差值为 m 的倍数的强度会落入同一频段,因此频段编号等价于强度对 m 取余的值(即 a_i % m)。因此,遍历所有 a_i,统计每个余数出现的次数(用长度为 m 的数组或哈希表),最后取最大出现次数即为答案。
代码:
cpp
#include<bits/stdc++.h>
#define int long long
#define dd double
#define str string
#define el cout << '\n'
#define re return
#define ff first
#define ss second
#define pll pair<int,int>
#define pdd pair<dd,dd>
#define all(x) x.begin(),x.end()
#define pb push_back
using namespace std;
void go(){
int n, m;cin>>n>>m;
map<int, int>cnt;
for(int i=1;i<=n;i++){
int x;cin>>x;
cnt[x%m]++;
}
int ans = 0;
for(auto [num, c]:cnt){
ans = max(ans, c);
}
cout<<ans;el;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
int _=1;
cin >>_;
while(_--){
go();
}
return 0;
}
//ncccpc
B
题目:oj | 什么,这题是1700!!?
思路:
首先我们可以发现如果c[1]=1或者c[n]=1,那么我们必定失败,因为我们不可能选择l=0,r=n,这样说明我们无法在1地区和n地区部署防御兵。
然后我们还可以发现如果对于一个地区如果它是最高的或者最低的,也就是他为高度为1或者高度为n,并且它的c[i]=1。
那么我们没法找到一组l和r,让他的高度夹在l高度和r高度中间,那么它就无法部署防御兵。
排除这2种情况,我们就一定可以防守成功了,我们首先找到最高的位置和最低的位置,假设最低的位置是j,最高的位置是k。
我们可以直接用5次操作,反正没有限制,然后我们假设位置是这样的。上面代表s,下面代表下标
0000000000000000000000
1######j######k######n
第一次操作我们可以选择j和k,这样j到k的地方就都变成1了,那么就变成
0000000011111100000000
1######j######k######n
第二次操作我们可以选择1和k,这样在左半部分中,高度大于位置1并且低于位置k的地方就都变成1了。
第三次操作我们可以选择1和j,这样在左半部分中,高度大于位置j并且低于位置1的地方就都变成1了。
这时你会发现通过操作二和操作三,你让左部分全变成1了也就是
0111111011111100000000
1######j######k######n
同样的操作我们在右半部分实现。
第四次操作我们可以选择k和n,这样在右半部分中,高度大于位置n并且低于位置k的地方就都变成1了。
第五次操作我们可以选择j和n,这样在右半部分中,高度大于位置j并且低于位置n的地方就都变成1了。
最后我们发现
0111111011111101111110
1######j######k######n
由于我们排除了最开始说的2种情况,所以这样的字符串s肯定能防守成功。
代码:
cpp
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll i,j,k,t,n,a[200005];
string s;
void go(){
cin>>n;
k=1;
for(i=1;i<=n;i++){
cin>>a[i];
}
cin>>s;
s=" "+s; //这里给s位置调整一下
if(s[1]=='1'||s[n]=='1'){//如果中了第一种情况就输出-1
cout<<-1<<'\n';
return;
}
for(i=1;i<=n;i++){//检查有没有中第二种情况
if(s[i]=='1'&&(a[i]==1||a[i]==n)){
k=0;
}
}
if(k==0){//如果中了第二种情况就输出-1
cout<<-1<<'\n';
return;
}else{
cout<<5<<'\n';
for(i=1;i<=n;i++){
if(a[i]==1){
j=i;
}
if(a[i]==n){
k=i;
}
}
if(j>k){//保证j位置在左,k位置在右
swap(j,k);
}
cout<<j<<' '<<k<<'\n';
cout<<1<<' '<<k<<'\n';
cout<<1<<' '<<j<<'\n';
cout<<j<<' '<<n<<'\n';
cout<<k<<' '<<n<<'\n';
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>t;
while(t--){
go();
}
return 0;
}
C
题目:oj | 量化密钥比对
思路:
读入两个字符串,分别以小数点分开两部分处理,整数部分去除前导0,小数部分去除后导0,再合在一起比较是否相同即可。
代码:
cpp
#include<bits/stdc++.h>
#define int long long
#define dd double
#define str string
#define el cout << '\n'
#define re return
#define ff first
#define ss second
#define pll pair<int,int>
#define pdd pair<dd,dd>
#define all(x) x.begin(),x.end()
#define pb push_back
using namespace std;
pair<str, str> split_dot(str s){
bool dot = 0;
str f = "",e = "";
for(char c:s){
if(c=='.'){
dot = 1;
continue;
}
if(!dot){
f += c;
}else{
e += c;
}
}
return {f, e};
}
str cut_f0(str s){
str ns = "";
bool n0 = 0;
for(char c:s){
if(c !='0'){
n0 = 1;
}
if(n0){
ns += c;
}
}
return (ns.empty()? "0":ns);
}
str cut_e0(str s){
while (!s.empty() and s.back()=='0')
{
s.pop_back();
}
return (s.empty()? "0":s);
}
void go(){
str a, b;
cin>>a>>b;
auto [fa, ea] = split_dot(a);
auto [fb, eb] = split_dot(b);
str sa = cut_f0(fa) + "." + cut_e0(ea);
str sb = cut_f0(fb) + "." + cut_e0(eb);
cout<< (sa==sb? "YES":"NO");el;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
int _=1;
cin >>_;
while(_--){
go();
}
return 0;
}
D
题目:oj | 神秘浮石矩阵
思路:
结论:对于题目中定义的操作,任意满足阶梯型的初始矩阵都必然在若干次操作后回到最初状态,因此答案恒为 YES。
证明要点(构造唯一的逆操作,说明操作为双射):
- 记一次操作为 f。若已知某次操作的结果矩阵 b,我们可以唯一地恢复操作前旋转后的矩阵 v:对每一列,将该列的非零元素(它们在 b 中一定位于列的底部)按从上到下的顺序取出并放回到该列的顶端(其余位置补零),即可还原 v。
- 再将 v 逆时针旋转 90° 就能唯一恢复操作前的矩阵 a。于是对于任意结果 b,逆过程是确定且唯一的,说明 f 在全集合上可逆,即 f 是一个双射(排列)。
- 在有限集合( n × n n \times n n×n 个格子的有效排列数有限)上,任何双射都是由若干个互不相交的有限循环组成。初始状态位于某个循环上,沿着 f 的迭代必然在循环长度步后回到初始状态。
因此对任意满足条件的输入,输出恒为 YES。
代码:
cpp
#include<bits/stdc++.h>
#define int long long
#define dd double
#define str string
#define el cout << '\n'
#define re return
#define ff first
#define ss second
#define pll pair<int,int>
#define pdd pair<dd,dd>
#define all(x) x.begin(),x.end()
#define pb push_back
using namespace std;
void go(){
int n; cin >> n;
//vector<vector<int>> a(n+1, vector<int>(n+1));
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
int x;cin>>x;
}
}
cout<<"YES";el;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
int _=1;
//cin >>_;
while(_--){
go();
}
return 0;
}
E
题目:oj | 密室刻印修补
思路:
把长度为10的字符串视作26进制数(a=0...z=25)。
- 将字符串从高位到低位转成整数 value。
- 计算 value + K,若超过最大值 26^10−1 返回 -1。
- 否则把新值按26进制还原为10个字母并输出。
注意使用64位整数避免溢出。
代码:
cpp
#include<bits/stdc++.h>
#define int long long
#define dd double
#define str string
#define el cout << '\n'
#define re return
#define ff first
#define ss second
#define pll pair<int,int>
#define pdd pair<dd,dd>
#define all(x) x.begin(),x.end()
#define pb push_back
using namespace std;
str s;
int K;
void go(){
int res = 0;
int up = 0;
for(int i=0;i<10;i++){
res = res*26 + s[i]-'a';
up = up*26 + 'z'-'a';
}
res += K;
if(res> up){
cout<<-1;el;re;
}
str ans = "";
for(int i=9;i>=0;i--){
int sum = powl(26, i);
int j = 0;
while (res >= sum)
{
res -= sum;
j++;
}
ans += (j+'a');
}
cout<<ans;el;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
int _=1;
//cin >>_;
while(cin>>s>>K){
go();
}
return 0;
}
F
题目:oj | 星环工程的任务链系统
思路:
任务链数量 = m! \times C_{n}^{m}
也就是从 n 中选 m(组合),再对选出的 m 个任务任意排列(排列数)。
可化简为:\frac{n!}{(n-m)!}
步骤:
- 预处理
fac[]与ifac[] - 逆元需用 快速幂 :x^{-1} = x^{MOD-2} \mod MOD,当且仅当
x与MOD互质。 - 公式使用:ans = fac[n] \times ifac[n-m] \mod MOD
代码:
cpp
#include <bits/stdc++.h>
using namespace std;
using int64 = long long;
const int64 MOD = 998244353;
// 快速幂求逆元
int64 mod_pow(int64 a, int64 e) {
int64 r = 1;
while (e) {
if (e & 1) r = r * a % MOD;
a = a * a % MOD;
e >>= 1;
}
return r;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
vector<pair<int,int>> queries(T);
int max_n = 0;
for (int i = 0; i < T; ++i) {
cin >> queries[i].first >> queries[i].second;
max_n = max(max_n, queries[i].first);
}
// 最大 n 的 factorial + ifac 预处理
vector<int64> fac(max_n + 1), ifac(max_n + 1);
fac[0] = 1;
for (int i = 1; i <= max_n; ++i) fac[i] = fac[i-1] * i % MOD;
ifac[max_n] = mod_pow(fac[max_n], MOD - 2); // n! 的逆元
for (int i = max_n; i >= 1; --i) ifac[i-1] = ifac[i] * i % MOD;
while (T--) {
int n = queries[T].first;
int m = queries[T].second;
if (m > n) {
cout << 0 << '\n';
continue;
}
// ans = n! / (n-m)! = fac[n] * ifac[n-m]
int64 ans = fac[n] * ifac[n - m] % MOD;
cout << ans << '\n';
}
return 0;
}
G
题目:oj | 火焰与铁蹄之路
思路:
排序取前k大的v求和即可。
代码:
cpp
#include<bits/stdc++.h>
#define int long long
#define dd double
#define str string
#define el cout << '\n'
#define re return
#define ff first
#define ss second
#define pll pair<int,int>
#define pdd pair<dd,dd>
#define all(x) x.begin(),x.end()
#define pb push_back
using namespace std;
struct p{
int t;
int v;
};
void go(){
int n,k;cin>>n>>k;
vector<p>a(n);
for(int i=0;i<n;i++){
cin>>a[i].t>>a[i].v;
}
sort(all(a), [](p a1, p a2){
return a1.v>a2.v;
});
int sum = 0;
for(int i=0;i<k;i++){
sum += a[i].v;
}
cout<<sum;el;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
int _=1;
cin >>_;
while(_--){
go();
}
return 0;
}
H
题目:oj | gq的图书馆之旅 - 3
思路:
输出520
代码:
cpp
#include <bits/stdc++.h>
using namespace std;
int main() {
cout << "520";
return 0;
}