summer 2014 Round 4 解题报告

Day 2:

  K-hash:

  这道题其实只要懂了后缀自动机就不难了。不过我还是做了很久。本来以为用个sort就可以让所有的节点按val从小到大排序,然后就能递推了。调试良久后发现排序后数组中每个元素的地址不会发生变化,只是值发生变化了,所以排序是没用的(因为p->o[i]和p->f都是指向的不变化的地址)。然后用priority_queue强行扭过了,速度还挺快,得瑟一下O(∩_∩)O~~

  (不知道zimpha怎么写的,跟开挂一样,又快内存又小,有机会的话找他请教一下。)

  这题其实直接按val值bfs一下就能得到按val值从小到大排序的点了...注意bfs的时候每次val值只能加1.

  

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <algorithm>
 6 #include <queue>
 7 #define FOR(i,l,r) for(int i=(l);i<=(r);i++)
 8 #define FORD(i,r,l) for(int i=(r);i>=(l);i--)
 9 #define rep(i,n) for(int i=0;i<(n);i++)
10 #define res(i,s) for(int i=0;((s)[i]);i++)
11 using namespace std;
12 typedef long long LL;
13 const int maxn=50001;
14 
15 char s[maxn];
16 int k;
17 
18 struct sam{
19     sam *o[10],*f;
20     int val;
21     LL v[32];
22 }ssam[maxn*2],*bt,*last; int sct;
23 sam *newd(int val)
24 {
25     sam *p=&ssam[sct++];
26     rep(i,10) p->o[i]=0;
27     p->f=0; p->val=val;
28     rep(i,k) p->v[i]=0;
29     return p;
30 }
31 void trans(char s)
32 {
33     int d=s-'0';
34     sam *p=last,*np=newd(p->val+1); last=np;
35     for (; p&&!p->o[d]; p=p->f) p->o[d]=np;
36     if (!p) np->f=bt;
37     else if (p->o[d]->val==p->val+1) np->f=p->o[d];
38     else
39     {
40         sam *q=p->o[d],*nq=newd(p->val+1);
41         memcpy(nq->o,q->o,sizeof(q->o));
42         nq->f=q->f; q->f=np->f=nq;
43         for (; p&&p->o[d]==q; p=p->f) p->o[d]=nq;
44     }
45 }
46 void cl(sam *p)
47 {
48     for (int i=(p==bt?1:0); i<10; i++)
49         if (p->o[i])
50         {
51             for (int j=0; j<k; j++)
52                 p->o[i]->v[(j*10+i)%k]+=p->v[j];
53         }
54 }
55 
56 LL ans[32];
57 void init() { sct=0; last=bt=newd(0); }
58 void bl(sam *t,string s)
59 {
60     cout<<s<<endl;
61     rep(i,10)
62         if (t->o[i])
63             bl(t->o[i],s+char('0'+i));
64 }
65 int main(){
66     while (scanf("%s%d",s,&k)!=EOF)
67     {
68         init();
69         res(i,s) trans(s[i]);
70         //bl(bt,"");
71         priority_queue<pair<int,int>, deque<pair<int,int> >, greater<pair<int,int> > > q;
72         rep(z,sct) q.push(make_pair(ssam[z].val,z));
73         bt->v[0]=1;
74         while (!q.empty()) cl(&ssam[q.top().second]),q.pop();
75         rep(i,k) ans[i]=0;
76         FOR (i,1,sct-1) rep(j,k) ans[j]+=ssam[i].v[j];
77         if (bt->o[0]) ans[0]++;
78         rep(i,k) printf("%s%lld", i==0?"":" ", ans[i]);
79         puts("");
80     }
81     return 0;
82 }
83 
84 //greater是最小堆,priority_queue默认是最大堆
View Code

Day 4:

  Fixed Point

  题目总结:

  这种数论动规的关键点是在“与上届相等的数的处理”上,只要这个弄懂了,这种题应该就都会做了。

  因为和上届相等的数最多只有一个,所以我用一个equal来记录是否有满足条件的上届。而其他小于上届的数用f数组储存。

  策略只有取1和取0。

  小于上届的数可以随便取。

  equal的状态转移要好好想想:

  当前位为1:取1则equal保留,取0则equal可以转移到f数组。

  当前位为0:取0则equal保留。取1就比上届大了,舍去。

  一般性总结:

  1.打草稿分析样例很有效果。

  2.直接用不加证明的结论这种习惯不好。这道题中以及Coprime Sequence中已经深有体会。

 
 1 #include <iostream>
 2 #include <cstdlib>
 3 #include <cstdio>
 4 #include <cstring>
 5 #define FOR(i,l,r) for(int i=(l);i<=(r);i++)
 6 #define FORD(i,r,l) for(int i=(r);i>=(l);i--)
 7 #define rep(i,n) for(int i=0;i<(n);i++)
 8 using namespace std;
 9 typedef long long LL;
10 typedef unsigned int ui;
11 ui get2[33];
12 
13 LL f[33][33];
14 LL gao(ui R, ui c, int k, int flag)
15 {
16     memset(f,0,sizeof(f));
17     LL equal=1; int gs0=0;
18     FORD (z,31,0)
19     {
20         //0
21         if (flag>=0 || !(c&get2[z]))
22         {
23             FOR (i,1,32-z) f[z][i]=f[z+1][i-1];
24             if (R&get2[z]) f[z][gs0+1]+=equal;
25         }
26         //1
27         if (flag<=0 || (c&get2[z]))
28         {
29             FOR (i,0,31-z) f[z][i]+=f[z+1][i];
30         }
31         if ((R&get2[z]) && !(flag<=0 || (c&get2[z]))) equal=0;
32         if (!(R&get2[z]) && !(flag>=0 || !(c&get2[z]))) equal=0;
33         gs0+=!(R&get2[z]);
34     }
35     LL ret=0;
36     FOR (i,0,32) if (abs(32-i-i)<=k) ret+=f[0][i];
37     if (abs(32-gs0*2)<=k) ret+=equal;//~~
38     return ret;
39 }
40 
41 ui L,R,c; int k;
42 LL gao0(int flag)
43 {
44     LL ret=gao(R,c,k,flag);
45     if (L) ret-=gao(L-1u,c,k,flag);
46     return ret;
47 }
48 
49 int main()
50 {
51     get2[0]=1; for (int i=1;i<=32;i++) get2[i]=get2[i-1]<<1;
52 
53     int T; scanf("%d",&T);
54     LL ans1,ans2,ans3;
55     FOR (z,1,T)
56     {
57         scanf("%u%u%u%d",&L,&R,&c,&k);
58         ans1=gao0(1);
59         if (c!=0) ans2=0; else ans2=gao0(0);
60         ans3=gao0(-1);
61         printf("Case %d: %lld %lld %lld
",z,ans1,ans2,ans3);
62     }
63     return 0;
64 }
Fixed Point 代码
原文地址:https://www.cnblogs.com/monmonde/p/3910779.html