给你 nn 个字符串,每个字符串最多包含 A - ZA−Z 这26个字母,KevenKeven 现在取了一些字符串,发现每个字母出现的次数都是 3 的倍数,KevenKeven 现在想要知道在满足每个字母出现的次数都是 3 的倍数的前提下,最多能取多少个字符串。
是真的没想到可以用dfs做
#include <bits/stdc++.h>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#define ll long long
using namespace std;
int n, m;
int a[15][26] = {0};
int c[26] = {0};
void bfs(int x, int k){
if(x >= n){
for(int i = 0; i < 26; i++) if(c[i] % 3) return;
m = max(m, k);
return;
}
for(int i = 0; i < 26; i++) c[i] += a[x][i];
bfs(x + 1, k + 1);
for(int i = 0; i < 26; i++) c[i] -= a[x][i];
bfs(x + 1, k);
}
int main(){
string b;
m = 0;
cin >> n;
for(int i = 0; i < n; i++){
cin >> b;
for(int j = 0; j < b.size(); j++){
a[i][b[j] - 'A']++;
}
}
bfs(0, 0);
cout << m << endl;
return 0;
}
即每个字符串都有 选与不选两种可能,穷尽所有情况。
#include<bits/stdc++.h>
#define lowbit(x) (x & -x)
using namespace std;
int t, n;
int main() {
scanf("%d", &t);
while(t --) {
scanf("%d", &n);
int ans = 0;
while(n) {
int x = n, gs = 0;
int ha = lowbit(x), haa = 0;
while(x) {
if(x == lowbit(x)) haa = lowbit(x); //只剩下最高位的时候。
x -= lowbit(x);
gs ++;
}
if(gs & 1) n ^= 1;
else n -= haa;
ans ++;
}
printf("%d\n", ans);
}
return 0;
}
末尾取反运用了异或1的操作。
lowbit:它的作用是求出n在表示成二进制的时候,最右边的1出现的位置对应的数
#include<iostream>
using namespace std;
int n;
int dp[4100][4100], a[4100];
int dfs(int l,int r,int time)
{
if(l==r) dp[l][r]=a[l]*time;
if(!dp[l][r])
dp[l][r] = max(time*a[l] + dfs(l+1, r, time+1), time*a[r] + dfs(l, r-1, time+1));
return dp[l][r];
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),a[i+n]=a[i];
int ans=0;
for(int i = 1;i <= n;i ++)
ans = max(ans, dfs(i, i+n-1, 1));
cout<<ans<<endl;
return 0;
}
想写dfs枚举所有情况结果理解错了题目的意思,本题并不是说往右跳了就不能往左跳,而是可以往左跳到还未被跳过的点,看了李大佬的答案后豁然开朗,即把问题划分成子问题,先求小区间最值,小区间被遍历后,因为可以往左或往右跳到还未跳到的点,就可以往左或者往右扩大最值。
很巧妙的做法是锤神使用的 32-__builtin_clz()函数,这里提供模拟做法
#include <bits/stdc++.h>
#define ll long long
#define MAXN 4005
#define Inf 0x3f3f3f3f
using namespace std;
int n,k;
int numx[30],numy[30];
bool check(int x, int y)
{
memset(numx,0,sizeof numx);
memset(numy,0,sizeof numy);
int cntx=0, cnty=0;
while(x)
{
numx[++cntx] = x%2;
x/=2;
}
while(y)
{
numy[++cnty] = y%2;
y/=2;
}
for(int s=1;cnty+1-s>=k;s++)
{
int sum=0;
for(int i=1;i<=cntx&&s+i-1<=cnty;i++)
{
if(numx[i]==numy[s+i-1])
sum++;
else
{
sum=0;
}
if(sum>=k) return true;
}
}
for(int s=1;cntx+1-s>=k;s++)
{
int sum=0;
for(int i=1;i<=cnty&&s+i-1<=cntx;i++)
{
if(numy[i]==numx[s+i-1])
sum++;
else
{
sum=0;
}
if(sum>=k) return true;
}
}
return false;
}
//可能x大,也可能y大
int main()
{
int ans = 0;
scanf("%d%d",&n,&k);
for(int i=1; i<n; i++)
{
for(int j=i+1; j<=n; j++)
{
if(i<j)
ans += check(i,j);
else
ans += check(i,j);
}
}
printf("%d\n",ans);
return 0;
}
即使用数组先使两个数之一滑动与另一数匹配,接着滑动另一个数去匹配。
使用二分查找答案,按hammer的思路,就是如果51可以那么52,53也可以,通过二分可以确定答案。
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
typedef long long LL;
const int N = 1e5+10;
int a[N], n, m;
bool check(int x)
{
int sum=0;
for(int i=1;i<=n;i++) sum+=(a[i]-1+x)/x;
return sum>m;
}
int main()
{
cin>>n>>m;
for(int i = 1, j;i <= n;i ++)
{
scanf("%d", &j);
a[j] ++;
}
sort(a+1, a+n+1, greater<int>());
while(!a[n])n --;
if(n>m)
{
cout<<-1;
return 0;
}
// cout<<-12312321;
int l=1,r=N;
while(l<r)
{
int mid=(l+r)/2;
if(check(mid)) l=mid+1;
else r=mid;
}
cout<<l<<endl;
return 0;
}
#include<string>
#include<iostream>
#include<math.h>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e5+5;
int a[maxn],len[maxn],dp[maxn],res[maxn];
int cnt;
int n;
//dp[i]记录当前字符串结尾的最长非递减(本题为递增子序对的个数。
int main()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
memset(len,0,sizeof(len));
dp[1]=a[1],len[1]=1;
cnt=1;
for(int i=2;i<=n;i++)
{
if(a[i]>dp[cnt])
{
cnt++;
len[i]=cnt;
dp[cnt]=a[i];
}
else
{
int pos=lower_bound(dp+1,dp+1+cnt,a[i])-dp;
len[i]=pos;
dp[pos]=a[i];
}
}
memset(res,0,sizeof(res));
for(int i=n;i>=1;i--)
{
if(len[i]==cnt||a[res[len[i]+1]]>a[i])
{
res[len[i]]=i;
}
}
cout<<cnt<<endl;
for(int i=1;i<cnt;i++)
cout<<res[i]<<" ";
cout<<res[cnt]<<endl;
return 0;
}
使用二分搜索更新值,对于dp数组,记录的是以当前字符结尾的连续序列的长度是多少。
最后在查找最小字典序的是时候,逆序更新数组,即两个下标如果位置一样的情况,在前面的下标一定会把在后面的下标更新。