A:
问你比第一个数大的数有几个,直接枚举
int main()
{
IOS;
int n;
cin >> n;
while(n -- )
{
int cnt = 0;
int x;
cin >> x;
for (int i = 0; i < 3; i ++ )
{
int a;
cin >> a;
if (a > x) cnt ++;
}
cout << cnt << endl;
}
return 0;
}
B:
每次可以删除任意位置的两个数,问你剩下的不重复的数最多有多少个。
首先:答案<=不重复数的个数。其次看奇偶性,如果不重复个数的奇偶性和n一样,那么答案就是不重复个数,否则-1
int main()
{
IOS;
int t;
cin >> t;
while (t -- )
{
int n;
cin >> n;
set<int> s;
for (int i = 0; i < n;i ++ )
{
int x;
cin >> x;
s.insert(x);
}
if(n % 2 == 0 && s.size() % 2 == 0 || n % 2 && s.size() % 2) cout << s.size() << endl;
else cout << s.size() - 1 << endl;
}
return 0;
}
C:
问你哪一个位置是皇后,皇后必须满足四个角都是'#',直接判断即可
const int mod = 1e9+7;
char g[10][10];
int main()
{
IOS;
int t;
cin >> t;
while (t -- )
{
for (int i = 0; i < 8; i ++ ) cin >> g[i];
for (int i = 1; i < 7; i ++ )
{
for (int j = 1; j < 7; j ++ )
{
if(g[i][j] == '#' && g[i - 1][j - 1] == '#' && g[i - 1][j + 1] == '#' && g[i + 1][j - 1] == '#' && g[i + 1][j + 1] == '#')
{
cout << i + 1 << ' ' << j + 1 << endl;
break;
}
}
}
}
return 0;
}
D:
给你一个初始时间和间隔t,问你在一天的时间之内,每次隔间t时间看一下当前的时间,如果当前时间的时和分符合回文数的话,那么cnt++,问最后的cnt。
首先把时间表示成一个整数,用整数去加间隔时间,再分离出当前时间的时和分,判断一下即可。
int main()
{
int t;
cin >> t;
while (t -- ){
int a, b, d;
int cnt = 0;
scanf("%d:%d", &a, &b);
cin >> d;
int be = a * 60 + b;
int x = be / 60;
int y = be % 60;
x = (x % 10 * 10) + x / 10;
if(x == y) cnt ++;
int k = be;
while(1){
be += d;
be %= 1440;
if(be == k) break;
int x = be / 60;
int y = be % 60;
x = (x % 10 * 10) + x / 10;
if(x == y) cnt ++;
}
cout << cnt << endl;
}
return 0;
}
E:
每次操作可以删除队头或者队尾,问你至少要删除多少次,使得剩下的元素之和为s。
就是问你哪个区间和为s且长度最大,那么删除次数就等于总长度减去区间长度。直接前缀和维护即可
要算某一个区间的和为k,且区间长度是最大的,则我们需要首先预处理出来前缀和
因为某一个区间的和等于a[r] - a[l - 1],对于每一个固定的a[i],我们需要找出它的a[l - 1]
出现的位置,那么区间长度就是对应下标减一减
const int N = 2e5 + 10;
int a[N];//前缀和数组
int b[N];//记录下标的数组
int main()
{
IOS;
int _;
cin >> _;
while(_ --){
int n, k;
cin >> n >> k;
int ans = n;
for (int i = 1; i <= n; i ++ )cin >> a[i];
for (int i = 1; i <= n; i ++ )a[i] += a[i - 1];
if(a[n] < k){
cout << -1 << endl;
continue;
}
for (int i = 1; i <= n; i ++ ) b[i] = -1;
b[0] = 0;
for (int i = 1; i <= n; i ++ ){
if(a[i] - k >= 0 && b[a[i] - k] != -1) ans = min(ans, n -(i - b[a[i] - k]));
if(b[a[i]] == -1) b[a[i]] = i;
}
cout << ans << endl;
}
return 0;
}
F:
问你是否有三个不同的数,满足三者和的个位是3.
那么我们可以读入的时候就只读入个位,那么枚举1个a[i],再枚举0-9中的第二位,再看一下第三位是否存在。
const int N = 300010;
int a[N];
int main()
{
IOS;
int _;
cin >> _;
while (_ -- ){
int n;
cin >> n;
int q[11] = {0};
for (int i = 0; i < n; i ++ )
{
int x;
cin >> x;
a[i] = x % 10;
q[x % 10] ++;
}
int ok = 0;
for (int i = 0; i < n; i ++ ){
q[a[i]] -- ;//用到了这一位,先减去
int t = (3 - a[i] + 10) % 10;//剩下两位的和
for (int x = 0; x < 10; x ++ ){//枚举剩下两位中的一位
int y = (t - x + 10) % 10;//这是最后一位
if(x == y && q[x] >= 2) ok = 1;//如果这两位相等的话,那么必须出现过至少2次
else if(x != y && q[x] && q[y]) ok = 1;//如果不相等并且都出现过
}
q[a[i]] ++;//恢复一下
}
if(ok) cout << "YES" << endl;
else cout << "NO" << endl;
}
return 0;
}
G:
问你是否存在多少个这样一个长度为k+1的序列,满足a[i] < 2 * a[i + 1];
我们可以处理出一个长度为n-1的序列b,b[i]=1则表示a[i] < 2 * a[i + 1],那么b显然是一个01序列。我们只需要看这个序列中有多少个长度大于等于k的连续子序列即可。显然我们可以从后往前dp一下,(其实也不用dp,就是一个很简单的事情)。然后循环一遍dp数组,看一下有多少位置的连续子序列长度大于等于k即可
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
#define rep(i,a,n) for (int i = a; i < n; i ++ )
#define repn(i,a,n) for (int i = a; i <= n; i ++ )
#define pb push_back
#define IOS ios::sync_with_stdio(false); cin.tie(0);cout.tie(0);
typedef long long ll;
typedef pair<int,int> PII;
ll gcd(ll a,ll b) { return b ? gcd(b,a % b) : a; }
const int mod = 1e9+7;
/*
根据题目我们可以直接创造出n-1长度的01序列,表示当前位置与下一个位置是否满足关系,然后只需要看当前位置连续1的个数是否>=k
*/
const int N = 200010;
//int a[N], b[N];//b数组记录bool判断
//int dp[N];//反向做一遍dp,看当前位置的连续1的个数
int main()
{
IOS;
int _;
cin >> _;
while(_ -- ){
int n, k;
cin >> n >> k;
int a[n] = {0}, b[n] = {0}, dp[n] = {0};
for (int i = 0; i < n; i ++ ) cin >> a[i];
for (int i = 0; i < n - 1; i ++ ) if(a[i] < 2 * a[i + 1]) b[i] = 1;
for (int i = n - 2; i >= 0; i -- ){
if(b[i] == 1) dp[i] = 1;
else dp[i] = 0;
if(dp[i + 1] && b[i]) dp[i] += dp[i + 1];
}
int cnt = 0;
for (int i = 0; i < n - 1; i ++ ) if(dp[i] >= k) cnt ++;
cout << cnt << endl;
}
return 0;
}
H:
一个赌博游戏,我们呢已经知道了接下来n次筛子能抛到几。现在有这样一个问题,由于我们只能在区间[l,, r]中参与游戏,我们认为我们没参与之前有1块钱,每次赢了可以翻一倍,输了/2,问我们在哪个区间[l,r],赌筛子抛到几(x),我们可以赚的钱最多(注意在这个区间,我们每次都是赌筛子抛到x);
思路:假设我们确定了我们赌博的点数k,那么如何能赢得最多呢,显然是在区间[l,r]中k出现的次数-其他出现的次数最大!也就是众数-其他数出现的次数最大!那么如何做呢?
我们可以事先维护出每一数字出现的位置,用map<int, vector<int>>来维护。
显示我们可以知道一个结论,如果想赢得多,这个区间的左右端点必须都赚钱,不然不就白白输了嘛。所以我们可以枚举每一个出现的数在他的位置区间内出现的次数 - 其他数的次数。
我们遍历map,当前赌的是x,假设我们固定了右端点r=a[i], l = a[j],则这个区间内一共有i - j + 1个x,一共有a[i] - a[j] + 1个数,所以次数就是 (i - j + 1) - (a[i] - a[j] + 1 - (i - j + 1))整理一下可以得到是2i - ai + 1 + aj - 2j。那么当我们遍历a的时候,显然2i - ai是固定的,我们只需要看当前这个i前面的aj - 2j最大是多少即可,动态维护一下就好了。下面见代码
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define y second
#define rep(i,a,n) for (int i = a; i < n; i ++ )
#define repn(i,a,n) for (int i = a; i <= n; i ++ )
#define pb push_back
#define IOS ios::sync_with_stdio(false); cin.tie(0);cout.tie(0);
typedef long long ll;
typedef pair<int,int> PII;
ll gcd(ll a,ll b) { return b ? gcd(b,a % b) : a; }
const int mod = 1e9+7;
/*
首先我们可以得到一个性质,这个区间的左右端点必然是赢钱的,不然就会莫名其妙亏了,然后呢这个问题的本质就是问你
区间内众数-非众数的个数最大是多少。
那么我们可以记录每一个元素出现的位置,用map<int, vector<int>> 来存储,vector是a,位置下标数组
然后我们去遍历这个map,固定了一个右端点ai,我们则可以发现,这个答案就是(i -j + 1)- (a[i] - a[j] + 1 - (i - j + 1)
== 2i - ai + 1 + aj - 2j,后面的j是不固定的
*/
const int INF = 0x3f;
int main()
{
IOS;
int _;
cin >> _;
while (_ -- ){
int n;
cin >> n;
map<int, vector<int>> v;
for (int i = 1; i <= n; i ++ ){
int x;
cin >> x;
v[x].pb(i);
}
int ans = 0, l, r;//ans是赌博猜的点数,l,r是区间
int mx = 0;//赚钱次数
for(auto [x, a] : v){
int t = -INF, pos;
for (int i = 0; i < a.size(); i ++ ){
if(a[i] - 2 * i > t){//如果说这个值大了就更新一下
t = a[i] - 2 * i;
pos = a[i];
}
int now = 2 * i - a[i] + t + 1;//现在可以赚钱的次数
if(now > mx){
mx = now, ans = x, l = pos, r = a[i];
}
}
}
cout << ans << ' ' << l << ' ' << r << endl;
}
return 0;
}