一次个人训练……果然一个人不是很强啊
进度[3/10] 场上2
HDU 6152 Friend-Graph
垃圾题目卡内存,做法就是强行暴力三个点,然后记得存边存bool
HDU 6153 A Secret
很经典的题目,题意是在S1串中找到S2串每个后缀出现的次数。
首先我们能想到一些求出现次数的算法比如KMP,EXKMP,SA,SAM……
当然这些算法挑一个写就行了。我用的是EXKMP,首先我们把两个串都翻转过来,这样之前求每个后缀的问题就转化成前缀出现的次数。我们直到extend数组有个神奇的性质就是他会把把模板串母串上的匹配情况记录下来,比如extend[i]等于3的时候就相当于长度为3的前缀……但是长度为2的前缀单独出现的时候,不会对长度为3的前缀产生影响。
我们跑一边EXKMP,然后把extend[i]每个数出现的次数记录下,从大到小记录后缀和,每个后缀对应的次数前缀和就是他总共出现的次数,相当于长度大于i的前缀 出现的次数 + 长度为i的字符单独出现的次数。
#include <bits/stdc++.h>
#define ll long long
#define next fuck
using namespace std;
const int MAXN = 1e6 + 10;
const ll mod = 1e9+7;
void pre_EKMP(char x[],int m,int next[])
{
next[0]=m;
int j=0;
while(j+1<m && x[j]==x[j+1])
j++;
next[1]=j;
int k=1;
for(int i=2; i<m; i++)
{
int p=next[k]+k-1;
int L=next[i-k];
if(i+L<p+1)
next[i]=L;
else
{
j=max(0,p-i+1);
while(i+j<m && x[i+j]==x[j])
j++;
next[i]=j;
k=i;
}
}
}
int next[MAXN],extend[MAXN];
int EKMP(char x[],int m,char y[],int n,int next[],int extend[])
{
pre_EKMP(x,m,next);
int j=0;
while(j<n && j<m && x[j]==y[j])
j++;
extend[0]=j;
int k=0;
for(int i=1; i<n; i++)
{
int p=extend[k]+k-1;
int L=next[i-k];
if(i+L<p+1)
extend[i]=L;
else
{
j=max(0,p-i+1);
while(i+j<n && j<m && y[i+j]==x[j])
j++;
extend[i]=j;
//cout<<j<<endl;
k=i;
}
}
}
char str1[MAXN],str2[MAXN];
ll cnt[MAXN];
int main()
{
int ca;
scanf("%d",&ca);
while(ca--)
{
int n,m;
scanf("%s%s",str1,str2);
n = strlen(str1);
m = strlen(str2);
reverse(str1,str1+n);
reverse(str2,str2+m);
pre_EKMP(str2,m,next);
memset(cnt,0x00,sizeof(cnt));
memset(next,0,sizeof(next));
memset(extend,0,sizeof(extend));
//cout<<str1<<'\n'<<str2<<'\n';
ll ans = 0;
EKMP(str2,m,str1,n,next,extend);
for(int i = 0;i<=n; i++)
{
//ans += extend[i];
//printf("%d ",extend[i]);
if(extend[i]) cnt[extend[i]]++;
}
// puts("");
cnt[m+1] = 0;
for(int i = m;i>=0;i--)
{
cnt[i] += cnt[i+1];
}
for(int i = m;i >= 0;i--)
{
ans += 1LL*i*(cnt[i]);
ans %= mod;
}
//puts("");
printf("%lld\n",ans);
}
return 0;
}
HDU 6156 Palindrome Function
一看就是数位DP的形式,但是搞了好久才会做……
我们设dp状态dp[pos][state][len] 代表现在构造到了pos位,现在的数字是不是回文的,回文的长度。
然后分成三种情况考虑,dp下就行
#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll dp[40][101][101][2];
int a[101],tmp[101];
ll dfs(int pos,bool state,int len,bool limit,int k)
{
if(pos < 0)
if(state) return k;
else return 1;
if(!limit && dp[k][pos][len][state] != -1)
return dp[k][pos][len][state];
int up = limit ? a[pos] : k-1;
ll ans =0;
for(int i = 0;i<=up;i++)
{
tmp[pos] = i;
if(i == 0 && len == pos)
{
ans += dfs(pos-1,state,len-1,limit && (i == up) ,k);
}
else if(state && pos < (len + 1) /2)
{
ans += dfs(pos-1,i == tmp[len - pos],len,limit && ( i == up),k);
}
else
{
ans += dfs(pos-1,state,len,limit &&( i == up),k);
}
}
if(!limit) dp[k][pos][len][state] = ans;
return ans;
}
ll solve(ll n,int k)
{
int pos = 0;
while(n)
{
a[pos++] = n % k;
n/=k;
}
return dfs(pos-1,1,pos-1,1,k);
}
int main()
{
int ca,cat = 1;
scanf("%d",&ca);
memset(dp,-1,sizeof(dp));
while(ca--)
{
ll L,R,l,r;
scanf("%I64d%I64d%I64d%I64d",&L,&R,&l,&r);
ll ans = 0;
for(int i = l;i<=r;i++)
{
ans += solve(R,i) - solve(L-1,i);
}
printf("Case #%d: %I64d\n",cat++,ans);
}
}