子串分值和:双指针
! 双指针的应用!
子串分值和
-
一开始考虑遍历:
-
无优化:算法时间复杂度太高了
-
遍历的算法优化: 采取区间分块&双指针&二分算法
-
-
思路贡献度
-
数字只有第一次出现的数字对子串有贡献度;
-
去重:set:每次储存set的长度
-
#include<iostream>
#include<set>
using namespace std;
int main()
{
string a;cin>>a;
int sum=0;
for(int i=0;i<a.size();i++)
{
set<int>s;
for(int j=i;j<a.size();j++)
{
s.insert(a[j]);
sum+=s.size();
}
}
cout<<sum;
return 0;
}
蒟蒻:
- 如何储存:
- 需要实现的操作:去重&寻找最小值&同一个物品有两个参数(set不好同时删除)->map 同时有两个参数 自动有序
#include<iostream>
#include<map>
using namespace std;
map<int,int>m1;
map<int,int>m2;
int main()
{
int n;cin>>n;
int sum=0;
for(int i=1;i<=n;i++)
{
int op;cin>>op;
if(op==1)
{
int w,t;cin>>w>>t;
if(!m1.count(w)&&!m2.count(t))
{
m1[w]=t;
m2[t]=w;
}
}
if(op==2)
{
m2.erase(m1.begin()->second);
m1.erase(m1.begin());
}
else if(op==3)
{
m1.erase(m2.begin()->second);
m2.erase(m2.begin());
}
}
for(int i=0;i<m1.size();i++)
{
sum+=m1[i];
}
cout<<sum;
return 0;
}
锦标赛:
思维题:
如果a[i]为有序数列 如果a[i]-a[i-1]>=k 则接下每一个都>=k 且最大的一定赢 sum++;
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
int n,k;cin>>n>>k;
int a[100005];
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
sort(a+1,a+1+n);
int sum=0;
for(int i=n;i>=2;i--)
{
if(a[i]-a[i-1]<=k) sum++;
else break;
}
cout<<sum;
return 0;
}
循环子串
回文字符或者本身是同一个字符【思维方法】
另一种方法:暴力
#include<bits/stdc++.h>
#include<string>
using namespace std;
int main()
{
int t;cin>>t;
while(t--)
{
int n;cin>>n;
string a;cin>>a;
string b=a+a;
int flag=0;
for(int len=1;len<=n;len++)
{
for(int i=0;i+len<=n;i++)
{
string s=b.substr(i,len);
reverse(s.begin(),s.end());
if(b.find(s)==b.npos)
{
flag=1;
break;
}
}
if(flag==1)
break;
}
if(flag==1) cout<<"NO";
else cout<<"YES";
cout<<endl;
}
return 0;
}
A-B数对:
简化一个是通过二分算法查找& 同时简化 寻找相同个数的——upper bound lower bound
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
long long n,c;cin>>n>>c;
long long a[200005];
long long sum=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
sort(a+1,a+1+n);
for(int i=1;i<=n;i++)
{
int l=lower_bound(a+1,a+1+n,a[i]+c)-a;
int r=upper_bound(a+1,a+1+n,a[i]+c)-a;
sum+=r-l;
}
cout<<sum;
return 0;
}c
可重排列:全排列dfs【优化:不要把相同数值的数展开】&stl 算法
dfs
#include<bits/stdc++.h>
using namespace std;
int sum=0;
vector<int>s;
unordered_map<int,int>p;
int n;
void dfs(int x)
{
if(x>sum)
{
for(int i=0;i<s.size();i++) printf("%d ",s[i]);
cout<<endl;
return;
}
for(int i=1;i<=n;i++)
{
if(p[i]) {
s.push_back(i);
p[i]--;
dfs(x+1);
s.pop_back();
p[i]++;
}
}
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
sum+=x;
p[i]=x;
}
dfs(1);
return 0;
}
stl
#include<bits/stdc++.h>
using namespace std;
vector<int>v;
int main()
{
int n;cin>>n;
for(int i=1;i<=n;i++)
{
int p;cin>>p;
for(int j=1;j<=p;j++) v.push_back(i);
}
do{
for(int i=0;i<v.size();i++)
{
cout<<v[i]<<" ";
}
cout<<endl;
}while(next_permutation(v.begin(),v.end()));
return 0;
}
数位计算:
简单思维题:!!longlong 开到unsigned 否则会超范围
#include<iostream>
using namespace std;
int main()
{
unsigned long long n;cin>>n;
unsigned long long sum=0;
unsigned long long i=9;
unsigned long long l=1;
for(i;i<=n;i=i*10+9)
{
long long x=(1+i/l*l)%998244353;
long long y=(i/l*l)%998244353;
sum=sum+(x*y/2)%998244353;
l*=10;
sum%=998244353;
}
unsigned long long x=(1+n-i%l)%998244353;
unsigned long long y=(n-i%l)%998244353;
sum=sum+(x*y/2)%998244353;
sum%=998244353;
cout<<sum;
return 0;
}
进制转换
- 注意输入和输出的格式
#include<iostream>
#include<string>
using namespace std;
int main()
{
int n,m;cin>>n>>m;
long long sum=0;
for(int i=1;i<=n;i++)
{
int a;cin>>a;
string b;cin>>b;
int l=1;
for(int j=b.size()-1;j>=0;j--)
{
if(b[j]>='0'&&b[j]<='9')
sum+=(b[j]-'0')*l;
if(b[j]>='A'&&b[j]<='Z')
sum+=(b[j]-'A'+10)*l;
if(b[j]>='a'&&b[j]<='z')
sum+=(b[j]-'a'+36)*l;
l*=a;
}
}
long long l=1;
long long k=sum;
while(k)
{
l*=m;
k/=m;
}
l/=m;
while(l>=1)
{
if(sum/l>=10&&sum/l<36)
cout<<(char)(sum/l-10+'A');
else if(sum/l>=36)
cout<<(char)(sum/l-36+'a');
else cout<<sum/l;
sum%=l;
l/=m;
}
return 0;
}
饿饿饭饭:
相同排除掉相同个数的数字 剩下的数字数量最小的为胜利【这个串不是所有串的子串则NO 否则则YES】
#include<iostream>
using namespace std;
int main()
{
int t;cin>>t;
int vis[200][200];
int n[200];
for(int i=1;i<=t;i++)
{
cin>>n[i];
for(int j=1;j<=n[i];j++)
{
int x;cin>>x;
vis[i][x]=1;
}
}
for(int i=1;i<=t;i++)
{
int l=1;
for(int j=1;j<=t;j++)
{
if(i==j) continue;
else
{
int flag=0;
for(int k=1;k<=100;k++)
{
//如果k在i中不出现 在j中出现
if(vis[i][k]==0&&vis[j][k]==1)
{
flag=1;
break;
}
}
if(flag==0)
{
l=0;
break;
}
}
}
if(l) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
巨大的牛棚
-
求最大的正方形: dp
#include<iostream> using namespace std; int a[1005][1005]; int f[1005][1005]; int main() { int n,t;cin>>n>>t; for(int i=1;i<=t;i++) { int x,y;cin>>x>>y; a[x][y]=1; } int m=-1; for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(!a[i][j]) f[i][j]=min(min(f[i][j-1],f[i-1][j]),f[i-1][j-1])+1; m=max(m,f[i][j]); } } cout<<m; return 0; }