A题
- 思路
分奇偶讨论。
偶数个 1 1 1:
最后一个位置存在 1 1 1,则除了第一个和最后一个,每次消掉一个 1 1 1,需要两次。
奇数个同理推导。 - 代码
ll x;scanf("%lld",&x);
bool flag = x%2;
int cnt = 0;
for (int i = 0 ;i <= 32 ;i ++) {
if ((x>>i)&1 == 1) cnt ++;
}
// cout<<cnt<<endl;
if (x == 4) {
printf("3\n");return;
}
if (!cnt) {
printf("0\n");return;
}
if (cnt & 1) {
if (flag) {
printf("%d\n",1+(cnt-1)*2);
} else {
printf("%d\n",3+(cnt-1)*2);
}
}
else {
if (flag) {
printf("%d\n",2+(cnt-2)*2);
} else {
printf("%d\n",cnt*2);
}
}
B题
- 题意
- 思路
动态规划-区间 d p dp dp
区间 d p dp dp 部分:
f [ i ] [ j ] f[i][j] f[i][j] 表示当前走完的点中 i i i 为左端点, j j j 为右端点时获得的最高分,确定了 i , j i,j i,j 之后,可以确定当前走完了 j − i + 1 j-i+1 j−i+1 步,并且当前停留在 i i i 或者 j j j 这个位置,那么可以得到递推方程
f [ i ] [ j ] = m a x ( f [ i − 1 ] [ j ] + a [ i ] ∗ ( j − i + 1 ) , f [ i ] [ j − 1 ] + a [ j ] ∗ ( j − i + 1 ) ) f[i][j]=max(f[i-1][j]+a[i]*(j-i+1),f[i][j-1]+a[j]*(j-i+1)) f[i][j]=max(f[i−1][j]+a[i]∗(j−i+1),f[i][j−1]+a[j]∗(j−i+1))
因为要么走左边,要么走右边
实现:
第一层枚举走的步数
l e n = 1 − t o − n len=1 -to -n len=1−to−n
第二层枚举左端点 i i i
i = 1 − t o − n − l e n + 1 i=1 - to - n-len+1 i=1−to−n−len+1
此时可以确定右端点 j = i + l e n − 1 j=i+len-1 j=i+len−1,然后正常递推方程
由于这是个环,有一个比较常见的处理技巧就是开 2 2 2 倍数组,
最后枚举左端点
i = 1 − t o − n i=1- to- n i=1−to−n
a n s = m a x ( a n s , f [ i ] [ i + n − 1 ] ) ans=max(ans,f[i][i+n-1]) ans=max(ans,f[i][i+n−1])
- 代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e4+10,mod=1e9+7;
template<typename T>
void Debug(T x,string s){
cout<<s<<": "<<x<<endl;
}
#define PII pair<int,char>
ll a[N*2];
ll dp[N][N];
void solve()
{
int n; cin>>n;
for (int i = 1;i <= n;i ++) {
cin>>a[i]; a[i+n] = a[i];
dp[i][i] = a[i];
dp[i+n][i+n] = a[i];
}
// memset(dp,0,sizeof(dp));
for (ll len = 2;len <= n;len ++) {
for (ll i = 1;i + len -1 <= 2*n;i ++) {
ll j = i + len - 1;
dp[i][j] = max(dp[i+1][j] + a[i]*len,dp[i][j-1]+a[j]*len);
}
}
ll ans = 0;
for (int i = 1;i <= n;i ++) {
ans = max(ans,dp[i][i+n-1]);
}
cout<<ans<<endl;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("a.txt", "r", stdin);
freopen("aout.txt", "w", stdout);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
// cin >> t;
t = 1;
while (t--)
solve();
}
注: d p dp dp 记得初始化。
C题
- 题意
- 思路
先预处理出 1 n 1~n 1 n 中对于每个数,其二进制形式中长度为 k k k 的子串有哪些,并转成十进制存储,此处是一个 n 2 n^2 n2的存储,然后 n 2 n^2 n2 枚举所有数对,对于任意一个数对 ( x , y ) (x,y) (x,y),我们需要判断是否匹配,可以直接枚举 x x x 中长度为 k k k 的子串所代表的的数字是否在 y y y 中出现过,若出现过则是匹配
这样处理的理论复杂度是 n 2 l o g n^2log n2log,并且,由于这个 l o g log log 特别小几乎可以忽略不计所以在实际运行中是跑的特别快的,如果写的比较优美,甚至可以两个 l o g log log 跑过去
- 代码
#include<bits/stdc++.h>
#define MAXN 2010
using namespace std;
int ka;
int f[MAXN][MAXN];
int ask(int x,int y)
{
int p=0,q=0,s=x,t=y;
while (s) s>>=1,p++;
while (t) t>>=1,q++;
if (p<ka||q<ka) return 0;
for (int i=0;i+ka-1<p;i++) {
for (int j=0;j+ka-1<q;j++) {
int now1=(x>>i),now2=(y>>j),cnt=0;
for (int k=0;k<min(ka,min(q-j,p-i));k++)
if ((now1&(1<<k))==(now2&(1<<k))){
cnt++;
if (cnt>=ka) return 1;
} else cnt=0;
}
}
return 0;
}
int main(){
int n,ans=0;
cin>>n>>ka;
for (int i=(1<<ka-1);i<=n;i++)
for (int j=i+1;j<=n;j++){
ans+=ask(i,j);
}
cout<<ans<<endl;
return 0;
}
D题
- 思路
直接扫一遍,碰到重复的加个 1 1 1 - 代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3e5+10,mod=1e9+7;
template<typename T>
void Debug(T x,string s){
cout<<s<<": "<<x<<endl;
}
#define PII pair<int,char>
PII a[N];
bool cmp (PII a, PII b){
if (a.second == b.second) return a.first < b.first;
return a.second < b.second;
}
void solve()
{
string s;cin >> s;
int ans = s.size();
for (int i = 1;i < s.size();i ++) {
if (s[i] == s[i-1]) {
ans ++;
}
}
cout<<ans<<endl;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("a.txt", "r", stdin);
freopen("aout.txt", "w", stdout);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while (t--)
solve();
}
E题
- 思路
二分检验 - 代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3e5+10,mod=1e9+7;
template<typename T>
void Debug(T x,string s){
cout<<s<<": "<<x<<endl;
}
#define PII pair<int,char>
int a[N];
void solve()
{
int n,m;cin>>n>>m;
map<int,int> jud;
for (int i = 1;i <= n;i ++) {
cin>>a[i]; jud[a[i]] ++;
}
if (jud.size() > m) {
cout<<-1<<endl;return;
}
vector<int> vec;
for (auto &xx:jud) {
vec.push_back(xx.second);
}
sort(vec.begin(),vec.end());
// cout<<vec[vec.size()-1]<<endl;
int l = 1,r = n;
while (l < r) {
int mid = (l+r)>>1;
int cnt = 0;
for (int i = 0;i < vec.size() ;i ++) {
cnt += vec[i]/mid;
if (vec[i]%mid!=0) cnt ++;
}
if (cnt > m) {
l = mid + 1;
}
else {
r = mid;
}
}
cout<<l<<endl;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("a.txt", "r", stdin);
freopen("aout.txt", "w", stdout);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
// cin >> t;
t = 1;
while (t--)
solve();
}
F题
- 思路
d p [ i ] [ j + k ] = d p [ i ] [ j ] + 1 dp[i][j+k] = dp[i][j]+1 dp[i][j+k]=dp[i][j]+1;
k ∈ 1... a [ i ] , i f a [ i ] > 0 k \in {1...a[i]}, ~~~if ~a[i]>0 k∈1...a[i], if a[i]>0 - 代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3e5+10,mod=1e9+7;
template<typename T>
void Debug(T x,string s){
cout<<s<<": "<<x<<endl;
}
#define PII pair<int,char>
int a[N];
int dp[N];
void solve()
{
int n;cin>>n;
for (int i = 1;i <= n;i ++) {
cin>>a[i];
}
memset(dp,0x3f3f3f3f,sizeof(dp));
dp[1] = 0;
for (int i = 1;i <= n;i ++) {
if (a[i] > 0) {
for (int j = 2;j <= n;j ++) {
if (j <= i + a[i]) {
dp[j] = min(dp[j],dp[i] + 1);
}
else break;
}
}
}
if (dp[n] == 0x3f3f3f3f) {
cout<<-1<<endl;
} else {
cout<<dp[n]<<endl;
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("a.txt", "r", stdin);
freopen("aout.txt", "w", stdout);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
// cin >> t;
t = 1;
while (t--)
solve();
}
G题
- 思路
枚举每个位置,二分找到并算出 a [ i ] − p , a [ i ] + p a[i]-p,a[i]+p a[i]−p,a[i]+p 区间长度。 - 代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6+10,mod=1e9+7;
template<typename T>
void Debug(T x,string s){
cout<<s<<": "<<x<<endl;
}
#define PII pair<int,char>
int a[N];
void solve()
{
int n,p;cin>>n>>p;
for (int i = 1;i <= n;i ++) cin>>a[i];
sort(a+1,a+1+n);
int cnt = 0;
for (int i = 1;i <= n;i ++) {
int tcnt = 0;
int l = lower_bound(a+1,a+1+n,a[i] - p) - a;
int r = upper_bound(a+1,a+1+n,a[i] + p) - a;
tcnt = (r-l);
cnt = max(cnt,tcnt);
}
cout<<cnt<<endl;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("a.txt", "r", stdin);
freopen("aout.txt", "w", stdout);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
// cin >> t;
t = 1;
while (t--)
solve();
}
H题
-
题意
-
思路
这题所有数据范围都是 1 e 6 1e6 1e6 以内的
首先子集的 g c d = x gcd=x gcd=x,那么这个子集里所有数都必然是 x x x 的倍数
反过来说如果子集里所有数都是 x x x 的倍数,那么这个子集 g c d gcd gcd 可能是 x x x 也可能是 x x x 的倍数
所以思路就有了,对于每次询问 x x x,查询 x x x, 2 x 2x 2x, 3 x 3x 3x……有无出现过,有就强行 g c d gcd gcd,在这个过程中,如果 g c d = x gcd=x gcd=x 了,即可停止
那么问题来了,如果每次操作都要一直查询,会不会导致复杂度变大,
我们可以开个数组标记,如果已经询问过 x x x 了,直接输出对应答案,否则查询
这样对于每个 x x x,都不会重复跑查询,那么他整个复杂度就是调和级数的复杂度,显然是可行的 -
代码
#include <stdio.h>
#include <string.h>
const int N = 1000005;
int n, m;
bool cur[N], res[N];
int gcd(int x, int y) {
while (y ^= x ^= y ^= x %= y);
return x;
}
int main() {
int task;scanf("%d", &task);
while (task--) {
scanf("%d%d", &n, &m);
memset(cur + 1, false, n);
memset(res + 1, false, n);
for (int i = 1; i <= n; ++i) {
int x;
scanf("%d", &x);
cur[x] = true;
}
for (int x = 1; x <= n; ++x) {
int d = 0;
for (int i = 1; i * x <= n; ++i) {
if (i * x >= 1 && cur[i * x]) {
d = gcd(d, i);
if (d == 1) {
//这样就保证了 gcd == x;
res[x] = true; break;
}
}
}
}
while (m--) {
int x;
scanf("%d", &x);
puts(res[x] ? "YES" : "NO");
}
}
return 0;
}
I题
- 思路
全排列
- 代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3e5+10,mod=1e9+7;
template<typename T>
void Debug(T x,string s){
cout<<s<<": "<<x<<endl;
}
#define PII pair<int,char>
int b[15];
int a[100];int cnt = 0;
void dfs(int cur,int n)//cur表示目前正在填的数,n表示总共要填的数
{
if(cur==n)//递归边界,说明填完了
{
vector<int> vec(n+1);
for(int i=0;i<n;i++)//一个一个的输出
{
vec[a[i]] = i+1;
}
for(int i = 1;i <= n;i ++) {
if (vec[i] < vec[b[i]]) {
return;
}
}
cnt++;
return;
}
for(int i=1;i<=n;i++)//把数字1-n填入
{
int ok=1;
for(int j=0;j<cur;j++)
{
if(a[j]==i) ok=0;
}
if(ok==1)
{
a[cur]=i;
dfs(cur+1,n);
}
}
}
void solve()
{
int n;cin>>n;
for (int i = 1;i <= n;i ++) {
cin>>b[i];
}
dfs(0,n);
cout<<cnt<<endl;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("a.txt", "r", stdin);
freopen("aout.txt", "w", stdout);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
// cin >> t;
t = 1;
while (t--)
solve();
}