I、Algorithm Choosing Mushrooms
theme:给定n,m,给定n个数,问这n个数中,连续的字符列的和是m的倍数最大可能是多少,最多连续几个数的和是m的倍数?
solution:暴力得到每个连续子序列复杂度:o(n*n),超时,由于是求连续数的和,自然想到前缀和,又求是m的倍数,不免想到余运算,而如果两个前缀和%m的余数相同,说明它们之前的数%m==0,即找到所求,所以我们遍历每一个前缀和%m,找到每个余数对应的最左与最右下标,便可以求出两个最大值。
#include<bits/stdc++.h>
using namespace std;
#define far(i,t,n) for(int i=t;i<n;++i)
typedef long long ll;
ll a[200020];
int pos[200020][2];
int main()
{
int n,m;
cin>>n>>m;
memset(pos,-1,sizeof(pos));
far(i,1,n+1)
{
scanf("%lld",&a[i]);
a[i]+=a[i-1];
}
far(i,1,n+1)
{
int x=a[i]%m;
if(pos[x][0]==-1)
{
pos[x][0]=i;
continue;
}
pos[x][1]=i;
}
ll ans1=0,ans2=0;
if(pos[0][1]!=-1)
ans1=a[pos[0][1]],ans2=pos[0][1];
else if(pos[0][0]!=-1)
ans1=a[pos[0][0]],ans2=pos[0][0];
far(i,1,m)
{
if(pos[i][0]==-1||pos[i][1]==-1)
continue;
ans1=max(ans1,a[pos[i][1]]-a[pos[i][0]]);
ans2=max(ans2,(ll)(pos[i][1]-pos[i][0]));
// cout<<i<<" "<<pos[i][0]<<" "<<pos[i][1]<<" "<<ans1<<" "<<ans2<<endl;
}
printf("%lld %lld\n",ans1,ans2);
return 0;
}
F、Cards with Numbers
theme:10^6次操作,每次要么给定一个[0,10^9]的数,要么询问一个[0,10^9]是否存在。
solution:如果数不是到10^9这么大的话,很容易用数组存,查询也很快。考虑用map,但次数又太多10^6,map是红黑树结构,会自动排序,复杂度为o(nlogn),会超时。所以可改用unordered_map(哈希散列原理),或用vector<bool>可开到10^9。或者自己写一个散列函数
vector+bool可开1e9数组(int不行)
#include<bits/stdc++.h>
using namespace std;
#define far(i,t,n) for(int i=t;i<n;++i)
typedef long long ll;
vector<bool> m(1e9+1);
int main()
{
int n;
int k,x;
scanf("%d",&n);
while(n--)
{
scanf("%d%d",&k,&x);
if(k==0)
m[x]=true;
else
{
if(m[x])
printf("yes\n");
else
printf("no\n");
}
}
return 0;
}
2、手动构造哈希函数(解决冲突)做
#include<bits/stdc++.h>
using namespace std;
#define far(i,t,n) for(int i=t;i<n;++i)
typedef long long ll;
int const p=1e6+3;
int Hash[p+5];
void setHash(int x)
{
int y=x%p;
while(Hash[y]!=-1)
{
y=(y+1)%p;
}
Hash[y]=x;
}
void getHash(int x)
{
int y=x%p;
while(Hash[y]!=-1)
{
if(Hash[y]==x)
{
printf("yes\n");
return;
}
y=(y+1)%p;
}
printf("no\n");
}
int main()
{
int n;
int k,x;
scanf("%d",&n);
memset(Hash,-1,sizeof(Hash));
while(n--)
{
scanf("%d%d",&k,&x);
if(k==0)
setHash(x);
else
getHash(x);
}
return 0;
}