3.25:今天早上做的还好,做了4题洛谷和1题poj,下午则做的不太多,只有一题poj。
3.26:今天在百忙之中(模拟赛),还是刷了一道poj的。模拟赛终于稳定了名次,Rank.7左右,恢复了之前的状态,希望能坚持,甚至做的更好。结尾追加题目与题解。
3.28:今天JPY讲了KMP,Trie和AC自动机,还是要多做题,搞懂它们。刷了poj7题,hdu1题。
3.26模拟赛题目&题解:
T1
题目大意:有n头牛,2头公牛中间至少要有k头母牛。问方案数对大质数取模值。(n<=100000)。
我的想法:不造为什么n这么小,按理说n为10000000都没问题的。其实吧,这题是一个不难的DP。数组f[]表示放到第i头牛的方案数,为了区分公牛母牛,我们设数组f[][0]来表示公牛,f[][1]来表示母牛,母牛由于没有限制条件,所以某一位的值为前一位公牛母牛的和,而公牛由于有限制所以只有n-k+1的地方可以有公牛出现,所以公牛某一位的值为n-k+1位公牛母牛个数和,最后答案即为f[n][1],f[n][0]相加,注意初始化f[i][1],f[i][0]都是1,1~k+1的公牛值是1。
则有:
f[i][x] i=1 2 3 4 5···
x=0 1 1 1 2 3
x=1 1 2 3 4 6
ans 2 3 4 6 9
其实可以优化到去掉后一维[x],但x小,且加上易于理解,就不去了,orz我的同学还有线段树,排列组合AC的。
T2
题目大意:有n组数,每一组有d个数,你最多可以用不超过k个任意数,请你找出你能表示的最多的连续组。(T组数据,T<=10,n<=1000000,d=1~3,k<=4)
我的想法:唉,orz爆〇了,其实写暴力可以得到30分优化的好可以60分+,但由于种种原因,我写wei了。。。讲一下标算。这个n较大n,但好像没有O(n)算法,只能退而求其次,O(n*lgn)成了首选,我们二分组数mid,从mid向两边尽可能的拓展,不断更新答案,为了避免TLE,我们当r-l已经小于ans时直接退出。
部分代码:
bool check(int x)
{
for(int i=1;i<=d;i++)if(mark[a[x][i]])return 1;
return 0;
}
void dfs(int l,int r,int lx,int rx,int k)
{
while(check(l-1)&&l>lx)l--;
while(check(r+1)&&rif(r-l>ansr-ansl)ansl=l,ansr=r;
if(r-l==ansr-ansl&&lif(k==K)return;
for(int i=1;i<=d;i++)
{
if(l!=lx)
{
mark[a[l-1][i]]=1;
dfs(l-1,r,lx,rx,k+1);
mark[a[l-1][i]]=0;
}
if(r!=rx)
{
mark[a[r+1][i]]=1;
dfs(l,r+1,lx,rx,k+1);
mark[a[r+1][i]]=0;
}
}
}
void solve(int l,int r)
{
if(r-lreturn;
if(l>r)return;
int mid=(l+r)>>1;
for(int i=1;i<=d;i++)
{
mark[a[mid][i]]=1;
dfs(mid,mid,l,r,1);
mark[a[mid][i]]=0;
}
solve(l,mid-1);solve(mid+1,r);
}
T3
题目大意:给你一个数x,求1~x中有多少数是可以被自己每一位上的数整除的。(多组数据,数据组数少于不多于10000,x<=9*10^18)
我的想法:嘿嘿嘿。。。我选择暴力50%。显然的是数位DP,但比较难构造,懒得分析了,233。
大致代码:
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define LL long long
LL dp[20][2525][55];
int digit[20];
int hash[2525];
int gcd(int a,int b)
{
if(b == 0) return a;
return gcd(b,a%b);
}
int calc_lcm(int a,int b)
{
return a/gcd(a,b)*b;
}
LL dfs(int pos,int mod,int lcm,bool limit)
{
LL ans = 0;
if(pos<=0) return mod % lcm == 0;
if(!limit && dp[pos][mod][hash[lcm]]!=-1) return dp[pos][mod][hash[lcm]];
int end = limit ? digit[pos] : 9;
for(int i=0;i<=end;i++)
{
ans += dfs(pos-1,(mod*10+i)%2520,i?calc_lcm(lcm,i):lcm,limit && (i==end));
}
if(!limit) dp[pos][mod][hash[lcm]] = ans;
return ans;
}
LL calc(LL a)
{
if(a<0) return 0;
int len = 0;
while(a>0)
{
digit[++len] = a%10;
a/=10;
}
LL ans = dfs(len,0,1,1);
return ans;
}
void init()
{
memset(dp,-1,sizeof(dp));
int id = 0;
for(int i=1;i*i<=2520;i++)
{
if(2520%i == 0)
{
hash[i] = id++;
if(i*i!=2520) hash[2520/i] = id++;
}
}
}
int main()
{
freopen("flower.in","r",stdin);
freopen("flower.out","w",stdout);
init();
int t;
LL x,y;
scanf("%I64d",&x);
while(scanf("%I64d",&x)!=EOF)
{
printf("%I64d\n",calc(x));
}
return 0;
}