还是只会做水题…………orz
【1】幸运序列
【问题描述】
Ly喜欢幸运数字,众所周知,幸运数字就是数字位上只有4和7的数字。但是本题的幸运序列和幸运数字完全没关系,就是一个非常非常普通的序列。哈哈,是不是感觉被耍了,没错,你就是被耍了。
Ly现在手上有一个长度为N的幸运序列a,他想这样子折腾这个序列:
1.如果已经折腾了k次了,就结束,否则找到一个最小的i,使得(a[i]=’4’ && a[i+1]=’7’) //0<i<N;
2.找不到这样的i就结束;
3.如果odd(i),令a[i+1]=a[i],否则令a[i]=a[i+1],继续第一步。
Ly想让你告诉他最后序列折腾成什么样子了。
需要注意的是,本题的序列从1开始编号
【输入文件】
第一行N,K;第二行N个数描述序列a。
【输出文件】
N个数,输出最后的序列。【输入样例】
7 44727447
【输出样例】
4427477【数据规模和约定】
100%的数据中N<=100000,K<=1E9。
【分析】
其实只有在(4, 4, 7) 和 (4, 7, 7) 的位置会出现循环 而且第一一个数的位置还必须是奇数
然后就可以华丽丽地模拟了 = = 因为后面的不会对前面产生影响 所以顺序处理就行了
#include <cstdio>
#include <iostream>
using namespace std;
int read()
{
int sign = 1, n = 0; char c = getchar();
while(c < '0' || c > '9'){ if(c == '-') sign = -1; c = getchar(); }
while(c >= '0' && c <= '9') { n = n*10 + c-'0'; c = getchar(); }
return sign*n;
}
int N, K;
int a[100005];
int main()
{
freopen("lucky.in","r",stdin);
freopen("lucky.out","w",stdout);
N = read(); K = read();
for(int i = 1; i <= N; ++i) scanf("%1d", &a[i]);
for(int i = 1; i <= N; ++i)
{
if(!K) break;
if(a[i] == 4)
{
if(i & 1 && a[i + 1] == 4 && a[i + 2] == 7) { a[i + 1] = K & 1 ? 7 : 4; break; }
if(i & 1 && a[i + 1] == 7 && a[i + 2] == 7) { a[i + 1] = K & 1 ? 4 : 7; break; }
if(a[i + 1] == 7)
{
if(i & 1) a[i + 1] = a[i];
else a[i] = a[i + 1];
--K;
}
}
}
for(int i = 1; i <= N; ++i) printf("%d", a[i]);
return 0;
}
【2】無名(noname)(字符串Hash)
【问题描述】
因为是蒯的题所以没想好名字,为什么要用繁体呢?去看《唐诗三百首》吧!题意很简单,给你一个串,求他有多少个不同的子串,满足前缀为A,后缀为B。
需要注意的是,串中所有的字母都是小写字母。
友情提示:如果你过不了样例,请注意是 不同 的子串。
【输入文件】
一共3行。第一行母串S;
第二行串A;
第三行串B。
【输出文件】
一个数,即有多少不同的子串。【输入样例】
ababababa
b
【输出样例】
4【数据规模和约定】
100%:length(S)<=2000;
length(A)<=2000;
length(B)<=2000;
30%:都少个0。
【分析】
数据范围比较小 所以就可以直接枚举子串了 首位置合法就在后面找一个合法的末位置 判断重复hash一下就行了。。
(窝这份代码在cena里会CE!!不要问我为什么 因为我也不知道为什么 = =鄙视我用指针?)
#include <cstdio>
#include <iostream>
#include <cstring>
#define id(i) (i - 'a')
using namespace std;
int read()
{
int sign = 1, n = 0; char c = getchar();
while(c < '0' || c > '9'){ if(c == '-') sign = -1; c = getchar(); }
while(c >= '0' && c <= '9') { n = n*10 + c-'0'; c = getchar(); }
return sign*n;
}
struct hash{
int son[26];
bool flag;
hash(){ flag = 0; memset(son, 0, sizeof(son)); }
}*t[2000005];
char S[2005], A[2005], B[2005];
int lens, lena, lenb, tot = 1, ans;
bool frt[2005], bhd[2005];
void count(int n, int pos, int lim)
{
if(!t[n]->flag && pos >= lim && bhd[pos - 1])
{
//printf("%d\n", pos);
t[n]->flag = 1;
++ans;
}
if(pos <= lens)
{
if(!t[n] -> son[id(S[pos])])
{
t[n] -> son[id(S[pos])] = ++tot;
t[tot] = new hash();
}
count(t[n] -> son[id(S[pos])], pos + 1, lim);
}
}
int main()
{
freopen("noname.in", "r", stdin);
freopen("noname.out", "w", stdout);
scanf("%s %s %s", S + 1, A + 1, B + 1);
lens = strlen(S + 1), lena = strlen(A + 1), lenb = strlen(B + 1);
for(int i = 1, j; i <= (lens - lena + 1); ++i)
{
for(j = 1; A[j] == S[i + j - 1] && j <= lena; ++j);
frt[i] = (j > lena);
}
for(int i = 1, j; i <= (lens - lenb + 1); ++i)
{
for(j = 1; B[j] == S[i + j - 1] && j <= lenb; ++j);
bhd[i + lenb - 1] = (j > lenb);
}
t[1] = new hash();
for(int i = 1; i <= lens; ++i)
if(frt[i]) count(1, i, i + max(lena, lenb));
printf("%d\n", ans);
return 0;
}
【3】poj2406 Power Strings(KMP)
题意:求出一个字符串最小循环节
这个玩意lrj好像是讲了的 = =就是如果n%(n-next[n]) == 0 则存在重复连续子串 长度为n-next[n]
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int Nmax = 1000005;
char s[Nmax];
int next[Nmax];
int main()
{
while(~scanf("%s", s + 1))
{
if(s[1] == '.') break;
int j = 0, len = strlen(s + 1);
for(int i = 2; s[i]; ++i)
{
while(j && s[i] != s[j + 1]) j = next[j];
if(s[i] == s[j + 1]) ++j; next[i] = j;
}
//for(int i = 1; s[i]; ++i) printf("%d ", next[i]);
if(len % (len - next[len])) puts("1");
else printf("%d\n", len / (len - next[len]));
}
return 0;
}
【4】poj1961 Period
题意:上面那题的升级版。。对于每一个i <= n 如果[1, i]中存在循环节 输出循环次数
注意输出格式 = =光荣PE 233
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int Nmax = 1000005;
char s[Nmax];
int next[Nmax];
int cas, N;
int main()
{
while(~scanf("%d", &N) && N)
{
scanf("%s", s + 1);
printf("Test case #%d\n", ++cas);
int j = 0;
for(int i = 2; s[i]; ++i)
{
while(j && s[i] != s[j + 1]) j = next[j];
if(s[i] == s[j + 1]) ++j; next[i] = j;
}
for(int i = 2; s[i]; ++i) if(next[i] && i % (i - next[i]) == 0)
printf("%d %d\n", i, i / (i - next[i]));
puts("");
}
return 0;
}