1001
http://acm.hdu.edu.cn/showproblem.php?pid=4907
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <stdlib.h>
#include <cmath>
#include <iomanip>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <cctype>
using namespace std;
const int maxn=200005;
bool vis[maxn];
int f[maxn];//第i时间得到的额外任务要在f[i]时间被执行,主要就是从当前任务向后找直到找到空闲时间为止,
int n,m;
int q;
int main()
{
int cas;
scanf("%d",&cas);
while(cas--)
{
scanf("%d%d",&n,&m);
memset(vis,0,sizeof(vis));
int t;
while(n--)
{
scanf("%d",&t);
vis[t]=1;
}
for(int i=maxn-1;i>=1;i--)
{
if(!vis[i])
f[i]=i;
else
f[i]=f[i+1];
}
while(m--)
{
scanf("%d",&q);
printf("%d\n",f[q]);
}
}
return 0;
}
1002
http://acm.hdu.edu.cn/showproblem.php?pid=4908
题意为 给定一个1 -N的排列,再给定一个数M(1<=M<=N),问有多少连续的长度为奇数子序列,使得M在其中为中位数(M在子序列中)。
比如样例
5 3
4 5 3 2 1 N=5, M=3
{3},{5,3,2},{4,5,3,2,1} 为符合题意的连续子序列....
当时做的时候把包含M的所有长度为0,1,2.......的连续子序列都枚举了出来,然后判断判断M是否是中位数,结果 果断超时.......
贴一下题解思路:
写了一堆字,优快云的排版太....了,贴图片把.
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <stdlib.h>
#include <cmath>
#include <iomanip>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <cctype>
using namespace std;
const int maxn=40002;
int sum[maxn];//从1到第i个数的和是多少
int d[maxn*2+1];//记录状态
int n,m;
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
sum[0]=0;
int pos;//m的位置
memset(d,0,sizeof(d));
int a;
for(int i=1;i<=n;i++)
{
scanf("%d",&a);
if(a==m)
pos=i;
if(a<m)
sum[i]=sum[i-1]-1;
else if(a>m)
sum[i]=sum[i-1]+1;
else
sum[i]=sum[i-1];
}
for(int i=0;i<pos;i++)
{
d[sum[i]+maxn]++;//前面的状态
// cout<<"sss"<<d[sum[i]+maxn]<<endl;
}
int ans=0;
for(int i=pos;i<=n;i++)
{
ans+=d[sum[i]+maxn];
}
printf("%d\n",ans);
}
return 0;
}
1003
http://acm.hdu.edu.cn/showproblem.php?pid=4909
解题思路:
题意为给定一个包含小写字母的序列,其中可能有一个'?‘,也可能没有,有的话最多只有一个,'?'可以删除,也可以替换为任意一个小写字母,问给定的序列中有多少个连续的子序列,保证所有小写字母出现的次数为偶数。
用一个26位二进制数来表示状态,每一位代表一个小写字母,关键是:
当一个状态出现时,后面又加上几个连续的字母,(状态的改变用状态的某一位异或1,)该状态又一次出现了,那么加上的那几个连续字母是符合题意的一个串,只有异或偶数倍某一位的状态才能回到本身, 比如一开始某一位的状态为0,异或一次0^1=1, 1^1=0...... 再比如是1, 1^1=0,0^1=1
要求记录每个状态出现的次数,那么26位,状态有 2^26-1个,用map<int,int>hash来模拟数组
hash[x] ,代表状态x出现的次数
对于有出现’?‘的串,可以分为三部分,?之前部分符合题意的串,之后部分符合题意的串,加上?以后符合题意的串,具体思路在代码注释中。
参考:http://blog.youkuaiyun.com/accelerator_/article/details/38363245#comments 大哭由于作者文章没有注释,代码看了好半天,才慢慢弄懂。。。。
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <map>
using namespace std;
const int maxn=20010;
char str[maxn];
int cas,n,p,x;
int ans;
map<int,int>hash;//hash[x]表示状态x出现了多少次
int main()
{
scanf("%d",&cas);
while(cas--)
{
hash.clear();
scanf("%s",str);
p=-1;
n=strlen(str);
for(int i=0;i<n;i++)
{
if(str[i]=='?')
{
p=i;
break;
}
}
ans=0;
if(p==-1)//一个状态出现过,后面又加了几个字母,而这个状态又重新出现了,说明后面加的
{ //每个字母都是偶数个,因为0^1=1,1^1=0
x=0;
hash[0]++;
for(int i=0;i<n;i++)
{
x^=(1<<(str[i]-'a'));
ans+=hash[x];//前面出现过hash[x]次,加上它
hash[x]++;
}
printf("%d\n",ans);
continue;
}
else
{
x=0;//计算'?'前面的串符合题意的有多少个
hash[0]++;
for(int i=0;i<p;i++)
{
x^=(1<<(str[i]-'a'));
ans+=hash[x];
hash[x]++;
}
hash.clear();//注意此时清空,后面的串是独立计算的
x=0;//计算'?'后面的串符合题意的有多少个
hash[0]++;
for(int i=p+1;i<n;i++)
{
x^=(1<<(str[i]-'a'));
ans+=hash[x];
hash[x]++;
}
x=0;
if(hash.count(x))
ans+=hash[x];
//花了N长时间终于明白上面这句话什么意思了
//把?看做空串(也可以理解为删除)和后面的串一块,有多少符合题意的,这时候状态是0
for(int i=0;i<26;i++)//枚举?的值与后面的串一块,有多少符合题意的
{
if(hash.count(x^(1<<i)))
ans+=hash[x^(1<<i)];
}
for(int i=p-1;i>=0;i--)//处理前部分时,和?以及后半部分建立了联系,注意一定是逆向,不能是正向,
{
x^=(1<<(str[i]-'a'));
if(hash.count(x))//寻找后半部分出现相同的状态,此时?为空, 这也是要逆向的原因
ans+=hash[x];
for(int j=0;j<26;j++)//枚举?的值
{
if(hash.count(x^(1<<j)))
ans+=hash[x^(1<<j)];
}
}
printf("%d\n",ans);
}
}
return 0;
}