问你比第一个数大的数有几个,直接枚举
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 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即可
#includeH: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 PII; ll gcd(ll a,ll b) { return b ? gcd(b,a % b) : a; } const int mod = 1e9+7; 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; }
一个赌博游戏,我们呢已经知道了接下来n次筛子能抛到几。现在有这样一个问题,由于我们只能在区间[l,, r]中参与游戏,我们认为我们没参与之前有1块钱,每次赢了可以翻一倍,输了/2,问我们在哪个区间[l,r],赌筛子抛到几(x),我们可以赚的钱最多(注意在这个区间,我们每次都是赌筛子抛到x);
思路:假设我们确定了我们赌博的点数k,那么如何能赢得最多呢,显然是在区间[l,r]中k出现的次数-其他出现的次数最大!也就是众数-其他数出现的次数最大!那么如何做呢?
我们可以事先维护出每一数字出现的位置,用map
显示我们可以知道一个结论,如果想赢得多,这个区间的左右端点必须都赚钱,不然不就白白输了嘛。所以我们可以枚举每一个出现的数在他的位置区间内出现的次数 - 其他数的次数。
我们遍历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最大是多少即可,动态维护一下就好了。下面见代码
#includeusing 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 PII; ll gcd(ll a,ll b) { return b ? gcd(b,a % b) : a; } const int mod = 1e9+7; const int INF = 0x3f; int main() { IOS; int _; cin >> _; while (_ -- ){ int n; cin >> n; map > 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; }



