标签:
1001
http://acm.hdu.edu.cn/showproblem.php?pid=5054
输出Yes只有一种情况.
#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> #define rd(x) scanf("%d",&x) #define rd2(x,y) scanf("%d%d",&x,&y) #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z) using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; int dx[8]={0,0,-1,1,1,1,-1,-1}; int dy[8]={1,-1,0,0,-1,1,-1,1}; //关键点是中点吧 int n,m,x,y; int main() { while(cin>>n>>m>>x>>y) { if(2*x==n&&2*y==m) cout<<"YES"<<endl; else cout<<"NO"<<endl; } return 0; }
1002
http://acm.hdu.edu.cn/showproblem.php?pid=5055
给出n个数字(每个数字0~9),用这n个数字组成一个数,要求不能有前导0,且最后一位必须是奇数。不能组成则输出-1.
可以构造出数的情况有: 只有一个数,且该数是奇数;n个数中大于0的数至少有2个,且n个数中存在奇数。
如果能满足的话,那么最小的奇数做数的最后一位,剩下的数从大到小排在前面就是所求的数。
写的时候逻辑有点乱.....这类题写的时候一定得考虑全面一些。
#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> #define rd(x) scanf("%d",&x) #define rd2(x,y) scanf("%d%d",&x,&y) #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z) using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; int dx[8]={0,0,-1,1,1,1,-1,-1}; int dy[8]={1,-1,0,0,-1,1,-1,1}; const int maxn=102; int num[maxn]; bool hasodd; int minodd; int n; bool cmp(int a,int b) { return a>b; } int main() { while(rd(n)!=EOF) { hasodd=0; minodd=100;//最小的奇数 int p=-1;//最小的奇数的位置 int cnt=0;//大于0的数字有多少个 for(int i=1;i<=n;i++) { rd(num[i]); if(num[i]>0) cnt++; if(num[i]&1) { hasodd=1; if(minodd>num[i]) { minodd=num[i]; p=i; } } } if(n==1) { if(hasodd) cout<<num[1]<<endl; else cout<<-1<<endl; continue; } if(cnt>=2&&hasodd) { swap(num[p],num[n]); sort(num+1,num+n,cmp); for(int i=1;i<=n;i++) cout<<num[i]; cout<<endl; } else cout<<-1<<endl; } return 0; }
1003
http://acm.hdu.edu.cn/showproblem.php?pid=5056
给出一个只有小写字母组成的字符串,然后给出一个数字k,问有多少子串满足 该子串中相同字母出现的次数不超过k。比如有一个子串 abac k=2的话,a的次数=2不超过k,b,c的次数均为1,也不超过k,所以这个子串就是符合要求的.
一个长度为n的字符串,子串一共有n(n+1)/2个,题目中n是100000,直接枚举肯定不行。
一开始想的也是枚举,枚举每个位置,判断以该位置开头的子串有多少个,两重循环,第二重循环就是长度了,一开始以为长度最多就是26(26个字母),复杂度还可以,但是忘了k的事...k不一定等于1啊,有可能很大....所以悲剧了,果断超时..
看到解题报告是 也是枚举每个位置,统计的则是以该位置为结尾的最大子串的长度,则是以该位置结尾的所有子串的个数,这个好理解,比如k=2, bcca,当位置为a时,满足条件的最大子串为 bcca,长度为4,那么满足的所有子串的个数也为4,分别为 bcca cca ca a。开辟两个指针,一个是枚举的位置,一个是满足该位置的最大串的起始位置,处治为该串的第一个位置。map<char,int>mp,记录每个字母出现的次数.下面以具体例子来说明是怎么工作的吧,解释不清楚.....
比如串 abbcbcc k=2
一开始位置为1, ‘a‘,起始指针start为1,mp[‘a‘]++, 该值满足<=k,ans+= i-start+1 ;即ans+=1,对应的串为a
后来位置为2,‘b‘, 起始指针start为1, mp[‘b‘]++, 满足条件, ans+= 2-start+1; 即ans+=2,对应的串为 b ab
后来位置为3,也满足条件,ans+=3,对应的串为 b bb abb
后来位置为4, 也满足条件,ans+=4;对应的串为 c bc bbc abbc
后来位置为5, mp[‘b‘]++,这时候mp[b]=3, 3>k,不符合条件,原因是b这个字母多了一个,要想以该位置为结尾,那么就得从前面去掉一个b,要求最大串,所以去掉最前面的一个b,同时更新起始位置, 这时候起始位置还是1,要想符合条件,就得移动该指针,mp[‘a‘]--,这是起始指针start对应的位置,start++, 这时候start=2,对应的字母为b,找到第一个b了,要把它去掉,所以再执行一次 mp[‘b‘]--,start++, 这时候start=3, 符合题意了, 满足的最大串为 bcb, ans+= 5-start+1,即ans+=3 ,对应的子串为 b cb bcb
后来同理....
从上面流程中可以看出start指针是一直往前的,这个效率比前面说的那个要高,有些位置满足的子串数可以0(1)来计算出
#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> #define rd(x) scanf("%d",&x) #define rd2(x,y) scanf("%d%d",&x,&y) #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z) using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; int dx[8]={0,0,-1,1,1,1,-1,-1}; int dy[8]={1,-1,0,0,-1,1,-1,1}; char s[100004]; map<char,int>mp; int len; int k; ll ans; int main() { int t;rd(t); while(t--) { mp.clear(); scanf("%s",s+1); rd(k); len=strlen(s+1); int start=1; ans=0; for(int i=1;i<=len;i++) { mp[s[i]]++; if(mp[s[i]]>k) { while(s[start]!=s[i]) { mp[s[start]]--; start++; } mp[s[start]]--; start++; } ans+=i-start+1; } printf("%I64d\n",ans); } return 0; }
标签:
原文地址:http://blog.csdn.net/sr_19930829/article/details/43638667