BYRBT

八十中集训解题报告

(持续更新中…………)

 

去八十中被屠成渣了,被屠得毫无还手之力,被屠得丧心病狂,停都停不下来,于是只好来写写题解了。

 

题目在openjudge上都有,自己去翻。

 

Day 1:

 

第一题:

 

这道概率题囧翻了…………卡精度………………

 

我们考虑我们枚举其中一个被解决的时候另外一个还剩多少体力,那么两个人收到伤害的次数都是固定的,假设第一个人被打了n次,第二个人被打了m次,那么就相当于将这m次不断插入到这n次之间的空去(不能插到第n次之后的空里面去),那么这就是个简单的组合计数了。

 

关于精度问题…………这个有点囧…………我们考虑第二个人的第m次可以由前一次推出来,然后将一些可能会导致精度下降的运算放到后面去做…………就差不多了吧…………

 

View Code
 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<cmath>
 5 
 6 using namespace std;
 7 
 8 const int maxn=20010;
 9 const double eps=1e-8;
10 
11 int n;
12 
13 double p;
14 
15 long double solve(int n,long double p)
16 {
17     long double ans=n,tmp=1;
18     for (int a=1;a<=n;a++)
19     {
20         tmp*=p*(n+a)/a*(1-p);
21         ans=ans*p+tmp*(n-a);
22     }
23     return ans*p;
24 }
25 
26 int main()
27 {
28     int t=0;
29     while (~scanf("%d%lf",&n,&p))
30     {
31           t++;
32           printf("Case %d: %.2lf\n",t,(double)(solve(n,p)+solve(n,1-p)));
33     }
34     
35     return 0;
36 }

 

第二题:

 

我一开始拿hash裸的…………其他人拿kmp裸的好像都比我裸的少了10分…………囧…………

 

我们考虑这个问题的本质吧,如果我们倒着做就相当于询问前缀能否拆为若干子串使得每一个都是选出的后缀的一个前缀。这样感觉好囧的样子,于是我们换个方向。假设我们从前往后做来构造这个后缀,那么我们处理到某个位置时相当于是构造出了这个目标后缀的一个前缀,我们考虑如何构造这个前缀。我们先对整个串做一次KMP,然后从前往后走。假设我们这时走到了一个位置p,我们已经得到了一个前缀s,然后考虑我们构造新串。如果我们发现当前串无法与已构造出的前缀进行任何一位的匹配,那么我们这个时候如果想要得到一个合法的串就只有把以后造出的前缀与当前这个串进行拼接形成新的前缀,否则如果能够匹配的话则代表当前串能够与原前缀进行匹配,则说明当前前缀合法。我们考虑我们如何检验这两个串是否能够匹配,这个可以用KMP做。考虑到我们要修改这个前缀,那么解决的办法就是每次对这个前缀暴力KMP,因为考虑到每个字符最多只被重做一次,所以依然是O(n)的。

 

View Code
 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 
 5 using namespace std;
 6 
 7 const int maxn=1000010;
 8 
 9 int n,fail[maxn];
10 
11 char s[maxn];
12 
13 int main()
14 {
15     int t;
16     scanf("%d",&t);
17     for (int p=1;p<=t;p++)
18     {
19         scanf("%s",s);
20         n=strlen(s);
21         fail[0]=0;
22         int b=0,last=1,lastl=1,nowp=0;
23         for (int a=1;a<n;a++)
24         {
25             while (b && s[nowp+b]!=s[a])
26                 b=fail[b-1];
27             if (s[nowp+b]==s[a]) b++;
28             if (!b)
29             {
30                 nowp=last-lastl;
31                 int nowl=a-nowp+1;
32                 for (int c=lastl;c<nowl;c++)
33                 {
34                     int d=fail[c-1];
35                     while (d && s[nowp+d]!=s[p+c])
36                         d=fail[d-1];
37                     if (s[nowp+d]==s[nowp+c]) d++;
38                     fail[c]=d;
39                 }
40                 lastl=nowl;
41                 last=a+1;
42                 b=fail[lastl-1];
43             }
44             else
45             {
46                 if (b==lastl)
47                 {
48                     last=a+1;
49                     b=fail[b-1];
50                 }
51             }
52         }
53         printf("Case %d: %d\n",p,n-last+lastl);
54     }
55     
56     return 0;
57 }

 

第三题:

 

神题…………考试的时候想多了所以打的表…………

 

那一大堆结论的证明自己去看当天的题解吧,我说说一种做法。

 

考虑一个质数的循环节既然是小于2n+2的,那么我们对每一个质因数的循环节暴力找出有多长即可了(因为最大的质因数也不大),然后考虑将各个质因数组合起来的方式,利用题解中那个公式就行了,总之一切皆为暴力。

 

View Code
 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 
 5 using namespace std;
 6 
 7 #ifdef unix
 8 #define LL "%lld"
 9 #else
10 #define LL "%I64d"
11 #endif
12 
13 const int maxn=1000000;
14 
15 int n;
16 
17 long long gcd(long long a,long long b)
18 {
19     if (a % b==0) return b;
20     else return gcd(b,a%b);
21 }
22 
23 int find(int mo)
24 {
25     int a=1,b=1,c=0,d=2;
26     while(true)
27     {
28         d++;
29         c=a+b;
30         if (c>=mo) c-=mo;
31         b=a;
32         a=c;
33         if (a==1 && b==0) return d-1;
34     }
35     return -1;
36 }
37 
38 int main()
39 {
40     int t;
41     scanf("%d",&t);
42     for (int p=1;p<=t;p++)
43     {
44         scanf("%d",&n);
45         if (n==1)
46         {
47             printf("1\n");
48             continue;
49         }
50         long long ans=1;
51         for (int a=2;a*a<=n;a++)
52             if (n % a==0)
53             {
54                 int nowans=find(a);
55                 n/=a;
56                 while (n%a==0)
57                 {
58                     n/=a;
59                     nowans*=a;
60                 }
61                 ans=ans/gcd(ans,nowans)*nowans;
62             }
63         if (n!=1)
64         {
65             int nowans=find(n);
66             ans=ans/gcd(ans,nowans)*nowans;
67         }
68         printf(LL "\n",ans);
69     }
70 }

 

Day 2:

 

第一题:

 

这题太囧了啊………………我树分治T到不行…………暴力的反而跑得硕快无比…………

 

我最后是这样做的,因为对于一棵子树只用考虑过根的路径,那么我们对每棵子树建一棵splay,维护它这棵子树中的每个节点到它的距离,进行合并的时候启发式合并即可。当然,你构造一根链我就GG了………………………然后你每次而二分个答案,然后找出比这个大的路径有多少就可以判定答案了………………判定可以用维护的那个splay乱搞就行了…………囧………………

 

View Code
  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<algorithm>
  5 
  6 using namespace std;
  7 
  8 const int maxn=50010;
  9 const int maxm=300010;
 10 const int maxp=5000010;
 11 const int INF=0x3f3f3f3f;
 12 
 13 int en,nowlimit,n,m,ans[maxm],now,cnt,z[maxn],nowl,l;
 14 
 15 bool flag;
 16 
 17 struct node
 18 {
 19     node *l,*r,*f;
 20     int size,cnt,v;
 21     node()
 22     {
 23         l=r=f=NULL;
 24         size=cnt=v=0;
 25     }
 26 }pp[maxp],*ppp=pp;
 27 
 28 node *newnode()
 29 {
 30     return ppp++;
 31 }
 32 
 33 struct splay_tree
 34 {
 35     node *root;
 36     void clear()
 37     {
 38         root=NULL;
 39     }
 40     void update(node *p)
 41     {
 42         p->size=p->cnt;
 43         if (p->l) p->size+=p->l->size;
 44         if (p->r) p->size+=p->r->size;
 45     }
 46     void rot_l(node *now)
 47     {
 48         node *x=now->r;
 49         now->r=x->l;
 50         x->l=now;
 51         if (now->f==NULL) root=x;
 52         else
 53         {
 54             if (now->f->l==now) now->f->l=x;
 55             else now->f->r=x;
 56         }
 57         x->f=now->f;
 58         now->f=x;
 59         if (now->r) now->r->f=now;
 60         update(now);
 61         update(x);
 62     }
 63     void rot_r(node *now)
 64     {
 65         node *x=now->l;
 66         now->l=x->r;
 67         x->r=now;
 68         if (now->f==NULL) root=x;
 69         else
 70         {
 71             if (now->f->l==now) now->f->l=x;
 72             else now->f->r=x;
 73         }
 74         x->f=now->f;
 75         now->f=x;
 76         if (now->l) now->l->f=now;
 77         update(now);
 78         update(x);
 79     }
 80     void splay(node *now,node *goal)
 81     {
 82         while (now->f!=goal)
 83         {
 84             node *f=now->f;
 85             node *ff=f->f;
 86             if (ff==goal)
 87             {
 88                 if (f->l==now) rot_r(f);
 89                 else rot_l(f);
 90             }
 91             else
 92             {
 93                 if (ff->l==f && f->l==now)
 94                 {
 95                     rot_r(ff);
 96                     rot_r(f);
 97                 }
 98                 if (ff->l==f && f->r==now)
 99                 {
100                     rot_l(f);
101                     rot_r(ff);
102                 }
103                 if (ff->r==f && f->l==now)
104                 {
105                     rot_r(f);
106                     rot_l(ff);
107                 }
108                 if (ff->r==f && f->r==now)
109                 {
110                     rot_l(ff);
111                     rot_l(f);
112                 }
113             }
114         }
115     }
116     void insert(int v)
117     {
118         if (root==NULL)
119         {
120             root=newnode();
121             root->cnt=1;
122             root->size=1;
123             root->v=v;
124         }
125         else
126         {
127             node *p=root,*lastp;
128             while (p)
129             {
130                 if (p->v==v)
131                 {
132                     p->cnt++;
133                     splay(p,NULL);
134                     return;
135                 }
136                 lastp=p;
137                 if (p->v<v) p=p->r;
138                 else p=p->l;
139             }
140             p=newnode();
141             p->cnt=p->size=1;
142             p->v=v;
143             p->f=lastp;
144             if (v<lastp->v) lastp->l=p;
145             else lastp->r=p;
146             splay(p,NULL);
147         }
148     }
149     int count(int v)
150     {
151         node *p=root;
152         int ans=0;
153         while (true)
154         {
155             if (v>p->v)
156             {
157                 if (p->r) p=p->r;
158                 else
159                 {
160                     splay(p,NULL);
161                     return ans;
162                 }
163             }
164             else
165             {
166                 ans+=p->cnt;
167                 if (p->r) ans+=p->r->size;
168                 if (p->v==v)
169                 {
170                     splay(p,NULL);
171                     return ans;
172                 }
173                 else
174                 {
175                     if (p->l) p=p->l;
176                     else
177                     {
178                         splay(p,NULL);
179                         return ans;
180                     }
181                 }
182             }
183         }
184         return ans;
185     }
186     void dfs(node *p)
187     {
188         if (!p) return;
189         dfs(p->l);
190         for (int a=1;a<=p->cnt;a++)
191         {
192             l++;
193             z[l]=p->v;
194         }
195         dfs(p->r);
196     }
197     void dfs2(node *p)
198     {
199         if (!p) return;
200         for (int a=1;a<=p->cnt;a++)
201         {
202             nowl++;
203             ans[nowl]=p->v;
204         }
205         dfs2(p->l);
206         dfs2(p->r);
207     }
208     void outit(int v)
209     {
210         node *p=root;
211         while (true)
212         {
213             if (v>p->v)
214             {
215                 if (p->r) p=p->r;
216                 else
217                 {
218                     splay(p,NULL);
219                     return;
220                 }
221             }
222             else
223             {
224                 for (int a=1;a<=p->cnt;a++)
225                 {
226                     nowl++;
227                     ans[nowl]=p->v;
228                 }
229                 if (p->r) dfs2(p->r);
230                 if (p->v==v)
231                 {
232                     splay(p,NULL);
233                     return;
234                 }
235                 else
236                 {
237                     if (p->l) p=p->l;
238                     else
239                     {
240                         splay(p,NULL);
241                         return;
242                     }
243                 }
244             }
245         }
246     }
247 }tree[maxn];
248 
249 struct edge
250 {
251     int e,d;
252     edge *next;
253 }*v[maxn],ed[maxn<<1];
254 
255 void add_edge(int s,int e,int d)
256 {
257     en++;
258     ed[en].next=v[s];v[s]=ed+en;v[s]->e=e;v[s]->d=d;
259 }
260 
261 void merge(splay_tree &t1,splay_tree &t2,int limit)
262 {
263     if (t1.root->size<t2.root->size) swap(t1,t2);
264     l=0;
265     t2.dfs(t2.root);
266     for (int a=1;a<=l;a++)
267         cnt+=t1.count(nowlimit+2*limit-z[a]);
268     for (int a=1;a<=l;a++)
269         t1.insert(z[a]);
270 }
271 
272 void getans(splay_tree &t1,splay_tree &t2,int limit)
273 {
274     if (t1.root->size<t2.root->size) swap(t1,t2);
275     l=0;
276     t2.dfs(t2.root);
277     for (int a=1;a<=l;a++)
278     {
279         int lastl=nowl;
280         t1.outit(nowlimit+2*limit-z[a]);
281         for (int b=lastl+1;b<=nowl;b++)
282             ans[b]+=z[a]-2*limit;
283     }
284     for (int a=1;a<=l;a++)
285         t1.insert(z[a]);
286 }
287 
288 void dfs(int now,int pre,int dist)
289 {
290     tree[now].insert(dist);
291     for (edge *e=v[now];e;e=e->next)
292         if (e->e!=pre)
293         {
294             dfs(e->e,now,dist+e->d);
295             if (flag) getans(tree[now],tree[e->e],dist);
296             else merge(tree[now],tree[e->e],dist);
297         }
298 }
299 
300 void check(int limit)
301 {
302     cnt=0;
303     nowlimit=limit;
304     for (int a=1;a<=n;a++)
305         tree[a].clear();
306     dfs(1,0,0);
307 }
308 
309 int main()
310 {
311 
312     scanf("%d%d",&n,&m);
313     for (int a=1;a<n;a++)
314     {
315         int s,e,d;
316         scanf("%d%d%d",&s,&e,&d);
317         add_edge(s,e,d);
318         add_edge(e,s,d);
319     }
320     int l=0,r=INF;
321     while (l+1!=r)
322     {
323         int mid=(l+r)>>1;
324         check(mid);
325         if (cnt>m) l=mid;
326         else r=mid;
327     }
328     flag=true;
329     check(r);
330     sort(ans+1,ans+m+1);
331     for (int a=m;a>=1;a--)
332         printf("%d\n",ans[a]);
333 
334     return 0;
335 }

 

第二题:

 

DP。

 

考虑对人员安排顺序固定了的一个序列,我们可以用f[i][j][k]表示前i个人放在了前j个位置且最后d个位置的的状态为k的方案数,这个dp还是比较水的。

 

然后我们考虑如何定序,假设我们有一个已有序列,那么我们需要放入下一个人,考虑由于每个人与他的朋友的距离都不能超过d,那么我们下一个放入的人一定是与已在序列中是朋友数最多的人(感觉很显然),如果有多个这样的人,那么我们需要放入的就是这些人中与不在序列中的人朋友最少的(还是很显然),如果有多个这样的人,那么他们是同构的,那么这个时候就把他们都加入序列,因为他们是同构的,也就是说当我们确定了第一个人是谁之后,整个序列也随之确定,那么问题迎刃而解。

 

View Code
  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<algorithm>
  5 
  6 using namespace std;
  7 
  8 const int maxn=52;
  9 const int maxm=110;
 10 const int maxd=8;
 11 const int mo=1000000007;
 12 const int INF=0x3f3f3f3f;
 13 
 14 #define inc(a,b) {(a)+=(b);if ((a)>=mo) (a)-=mo;}
 15 
 16 int in[maxn],to[maxn],f[maxn][maxm][1<<maxd],q[maxn],n,m,d;
 17 
 18 char s[maxn][maxn];
 19 
 20 bool use[maxn];
 21 
 22 bool check()
 23 {
 24     for (int a=1;a<=n;a++)
 25         for (int b=a-1;b>=1;b--)
 26             if (!s[q[a]][q[b]])
 27             {
 28                 for (int c=b-1;c>=1;c--)
 29                     if (s[q[a]][q[c]]) return false;
 30                 break;
 31             }
 32     for (int a=1;a<=n;a++)
 33         for (int b=a-d-1;b>=1;b--)
 34             if (s[q[a]][q[b]]) return false;
 35     return true;
 36 }
 37 
 38 
 39 int dp()
 40 {
 41     if (!check()) return 0;
 42     int ans=0;
 43     memset(f,0,sizeof(f));
 44     for (int a=1;a<=m;a++)
 45         f[1][a][1]=1;
 46     for (int a=1;a<n;a++)
 47         for (int b=a;b<=m;b++)
 48             for (int c=0;c<(1<<d);c++)
 49                 if (f[a][b][c])
 50                 {
 51                     if (s[q[a]][q[a+1]])
 52                     {
 53                         int nowp=a-1;
 54                         while (nowp && s[q[nowp]][q[a+1]])
 55                             nowp--;
 56                         nowp++;
 57                         int nows=c;
 58                         int cnt=0,p=-1;
 59                         while (nows)
 60                         {
 61                             if (nows&1) cnt++;
 62                             nows>>=1;
 63                             p++;
 64                             if (nowp+cnt==a+1)
 65                             {
 66                                 int pp=0,nows=c,cntt=0,uf=-INF;
 67                                 while (nows)
 68                                 {
 69                                     if (nows&1) cntt++;
 70                                     if (!s[q[a-cntt+1]][q[a+1]])
 71                                     {
 72                                         uf=b-pp;
 73                                         break;
 74                                     }
 75                                     pp++;
 76                                     nows>>=1;
 77                                 }
 78                                 for (int e=max(uf+d+1,b+1);e<=b-p+d;e++)
 79                                     inc(f[a+1][e][(1|((c&((1<<(d+b-e))-1))<<(e-b)))&((1<<d)-1)],f[a][b][c]);
 80                                 break;
 81                             }
 82                         }
 83                     }
 84                     else
 85                     {
 86                         for (int e=b+d+1;e<=m;e++)
 87                             inc(f[a+1][e][1],f[a][b][c]);
 88                     }
 89                 }
 90     for (int a=n;a<=m;a++)
 91         for (int b=0;b<(1<<d);b++)
 92             if (f[n][a][b]) inc(ans,f[n][a][b]);
 93     return ans;
 94 }
 95 
 96 int dfs(int nowp)
 97 {
 98     if (nowp>n) return dp();
 99     int nowans=0,nowinmax=-1,nowoutmin=INF;
100     for (int a=1;a<=n;a++)
101         if (!use[a])
102         {
103             if (in[a]>nowinmax)
104             {
105                 nowinmax=in[a];
106                 nowoutmin=to[a]-in[a];
107             }
108             if (in[a]==nowinmax && nowoutmin>to[a]-in[a]) nowoutmin=to[a]-in[a];
109         }
110     int cnt=0;
111     for (int a=1;a<=n;a++)
112         if (!use[a] && in[a]==nowinmax && nowoutmin==to[a]-in[a])
113         {
114             cnt++;
115             q[nowp+cnt-1]=a;
116             use[a]=true;
117         }
118     for (int a=nowp;a<=nowp+cnt-1;a++)
119         for (int b=1;b<=n;b++)
120             in[b]+=s[q[a]][b];
121     nowans=dfs(nowp+cnt);
122     for (int a=1;a<=cnt;a++)
123         nowans=(long long)nowans*a%mo;
124     for (int a=nowp;a<=nowp+cnt-1;a++)
125         for (int b=1;b<=n;b++)
126             in[b]-=s[q[a]][b];
127     for (int a=nowp;a<=nowp+cnt-1;a++)
128         use[q[a]]=false;
129     return nowans;
130 }
131 
132 int main()
133 {
134 
135     scanf("%d%d%d",&m,&n,&d);
136     for (int a=1;a<=n;a++)
137         scanf("%s",s[a]+1);
138     for (int a=1;a<=n;a++)
139         for (int b=1;b<=n;b++)
140             if (s[a][b]=='Y') s[a][b]=1,to[a]++;
141             else s[a][b]=0;
142     int ans=0;
143     for (int a=1;a<=n;a++)
144     {
145         q[1]=a;
146         for (int b=1;b<=n;b++)
147             in[b]+=s[a][b];
148         use[a]=true;
149         inc(ans,dfs(2));
150         use[a]=false;
151         for (int b=1;b<=n;b++)
152             in[b]-=s[a][b];
153     }
154     printf("%d\n",ans);
155 
156     return 0;
157 }

 

第三题:

 

这题jzp讲了一种logn的做法,但是没听懂…………囧…………

 

这道题其实有sqrt(n)的做法,因为考虑我们可以暴力出前sqrt(n)个数的值,那么考虑对于下sqrt(n)个数的值的一个分子增量范围是可以算出来的,并且会有一部分的增量比另外一部分多1,那么我们可以根据它们原来的关于模B的值排序,每次就可以二分出变化位置,从而推出下sqrt(n)个数的和。然后就可以做sqrt(n)次之后算出所有的答案。

 

View Code
 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 
 7 using namespace std;
 8 
 9 #ifdef unix
10 #define LL "%lld"
11 #else
12 #define LL "%I64d"
13 #endif
14 
15 const int maxn=100000;
16 const long long mo=1000000007;
17 
18 long long va,vb,vc,l,r;
19 
20 struct state
21 {
22     long long mod,x,y,z;
23     bool operator<(const state &a)const
24     {
25         return mod<a.mod;
26     }
27 }s[maxn],sum[maxn],bsum[maxn];
28 
29 int find(int size,long long delta_mod)
30 {
31     if (delta_mod<s[1].mod) return 1;
32     if (delta_mod>s[size].mod) return size+1;
33     int l=0,r=size;
34     while (l+1!=r)
35     {
36         int m=(l+r)>>1;
37         if (s[m].mod>=delta_mod) r=m;
38         else l=m;
39     }
40     return r;
41 }
42 
43 long long getans(int size,long long nowp)
44 {
45     long long delta_mod=nowp*va%vb;
46     int p=find(size,vb-delta_mod);
47     long long deltav=nowp*va/vb%mo;
48     long long ans=0;
49     long long delta=nowp;
50     p--;
51     if (p) ans=(ans+sum[p].z+sum[p].x*deltav%mo+delta*sum[p].y%mo+delta*deltav%mo*p%mo)%mo;
52     p++;
53     deltav++;
54     if (p<=size) ans=(ans+bsum[p].z+bsum[p].x*deltav%mo+delta*bsum[p].y%mo+delta*deltav%mo*(size-p+1)%mo)%mo;
55     return ans;
56 }
57 
58 long long solve(long long p)
59 {
60     if (p==0) return 0;
61     int size=(int)sqrt(p);
62     for (int a=1;a<=size;a++)
63     {
64         s[a].mod=(va*a+vc)%vb;
65         s[a].x=a;
66         s[a].y=(va*a+vc)/vb%mo;
67         s[a].z=s[a].x*s[a].y%mo;
68     }
69     sort(s+1,s+size+1);
70     sum[0].x=sum[0].y=sum[0].z=0;
71     for (int a=1;a<=size;a++)
72         sum[a].x=(sum[a-1].x+s[a].x)%mo,sum[a].y=(sum[a-1].y+s[a].y)%mo,sum[a].z=(sum[a-1].z+s[a].z)%mo;
73     bsum[size+1].x=bsum[size+1].y=bsum[size+1].z=0;
74     for (int a=size;a>=1;a--)
75         bsum[a].x=(bsum[a+1].x+s[a].x)%mo,bsum[a].y=(bsum[a+1].y+s[a].y)%mo,bsum[a].z=(bsum[a+1].z+s[a].z)%mo;
76     long long nowp=1,ans=0;
77     while (nowp+size-1<=p)
78     {
79         ans=(ans+getans(size,nowp-1))%mo;
80         nowp+=size;
81     }
82     for (long long a=nowp;a<=p;a++)
83         ans=(ans+(va*a+vc)/vb%mo*a%mo)%mo;
84     return ans;
85 }
86 
87 int main()
88 {
89     scanf(LL LL LL LL LL,&va,&vb,&vc,&l,&r);
90     printf(LL "\n",(solve(r)-solve(l-1)+mo)%mo);
91 
92     return 0;
93 }

 

Day 3:

 

第一题:

 

这道题最大的很好做,做最小的时候每次二分这个政党最少能够获得多少席位,然后用一个背包DP检验即可。

 

View Code
  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<algorithm>
  5 
  6 using namespace std;
  7 
  8 const int maxn=110;
  9 
 10 int z[maxn],s[maxn],v,n,m,maxv[maxn],sum,x[maxn],minv[maxn],f[2][maxn<<1];
 11 
 12 struct rec
 13 {
 14     int v,p;
 15     bool operator<(const rec &a)const
 16     {
 17         return v<a.v;
 18     }
 19 }y[maxn];
 20 
 21 int calc(int p)
 22 {
 23     for (int a=1;a<=n;a++)
 24         s[a]=0;
 25     for (int a=1;a<=m;a++)
 26     {
 27         pair<int,int> nowv=make_pair(0,1);
 28         int nowp=-1;
 29         for (int b=1;b<=n;b++)
 30             if (z[b]*20>=v && nowv.first*(s[b]+1)<nowv.second*z[b])
 31             {
 32                 nowv=make_pair(z[b],s[b]+1);
 33                 nowp=b;
 34             }
 35         if (nowp==-1) break;
 36         s[nowp]++;
 37     }
 38     return s[p];
 39 }
 40 
 41 bool check(int p,int goal)
 42 {
 43     int last=0,src=1,limit=m-goal;
 44     for (int a=1;a<=limit;a++)
 45         f[src][a]=v+1;
 46     f[src][0]=0;
 47     for (int a=1;a<=n;a++)
 48         if (a!=p)
 49         {
 50             src^=1;
 51             last^=1;
 52             for (int b=0;b<=limit;b++)
 53                 f[src][b]=f[last][b];
 54             for (int b=1;b<=limit;b++)
 55             {
 56                 int need=z[p]*b/(goal+1)+1;
 57                 if (z[p]*b%(goal+1)==0) need--;
 58                 if (need*20<v)
 59                 {
 60                     need=v/20;
 61                     if (need*20<v) need++;
 62                 }
 63                 need-=z[a];
 64                 if (need<0) need=0;
 65                 for (int c=b;c<=limit;c++)
 66                     f[src][c]=min(f[src][c],f[last][c-b]+need);
 67             }
 68         }
 69     return f[src][limit]<=v-sum;
 70 }
 71 
 72 int main()
 73 {
 74     scanf("%d%d%d",&v,&n,&m);
 75     for (int a=1;a<=n;a++)
 76         scanf("%d",&z[a]),sum+=z[a];
 77     for (int a=1;a<=n;a++)
 78     {
 79         z[a]+=v-sum;
 80         maxv[a]=calc(a);
 81         z[a]-=v-sum;
 82     }
 83     for (int a=1;a<=n;a++)
 84     {
 85         printf("%d",maxv[a]);
 86         if (a==n) printf("\n");
 87         else printf(" ");
 88     }
 89     for (int a=1;a<=n;a++)
 90         if (z[a]*20>=v || n==1)
 91         {
 92             int l=-1,r=m;
 93             while (l+1<r)
 94             {
 95                 int m=(l+r)>>1;
 96                 if (check(a,m)) r=m;
 97                 else l=m;
 98             }
 99             minv[a]=r;
100         }
101     for (int a=1;a<=n;a++)
102     {
103         printf("%d",minv[a]);
104         if (a==n) printf("\n");
105         else printf(" ");
106     }
107 
108     return 0;
109 }

 

 

第二题:

 

这题是神一般的DP,用f[i][j][k]表示从i点走到j点走了k步没有剩余字母的方案数,用g[i][j][k]表示从i点走到j点走了k步没有剩余字母且字母是在最后一步被消耗光的方案数,用h[i][j][k]表示从i点走到j点走了k步并且有字母剩余的方案数,然后三个互相推,就可以转移了。

 

View Code
  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<vector>
  5 #include<map>
  6 
  7 using namespace std;
  8 
  9 const int maxn=52;
 10 const int maxm=maxn*maxn;
 11 const int mo=10007;
 12 
 13 #define inc(a,b) {a+=b;if (a>=mo) a-=mo;}
 14 
 15 int en,n,m,k,g[maxn][maxn][maxn],f[maxn][maxn][maxn],h[maxn][maxn][maxn];
 16 
 17 int s1[maxm],e1[maxm],t1[maxm],cnt1;
 18 
 19 int s2[maxm],e2[maxm],t2[maxm],cnt2;
 20 
 21 struct edge
 22 {
 23     int e;
 24     char v;
 25     edge *next;
 26 }*v[maxn],ed[maxn*maxn],*v2[maxn];
 27 
 28 void add_edge(int s,int e,char c)
 29 {
 30     en++;
 31     ed[en].next=v[s];v[s]=ed+en;v[s]->e=e;v[s]->v=c;
 32     cnt1++;
 33     s1[cnt1]=s;e1[cnt1]=e;t1[cnt1]=c;
 34     if (c!='!') t1[cnt1]-='A'-1;
 35     else t1[cnt1]=0;
 36 }
 37 
 38 void add_edge2(int s,int e,char c)
 39 {
 40     en++;
 41     ed[en].next=v2[s];v2[s]=ed+en;v2[s]->e=e;v2[s]->v=c;
 42     cnt2++;
 43     s2[cnt2]=s;e2[cnt2]=e;t2[cnt2]=c-'a'+1;
 44 }
 45 
 46 int main()
 47 {
 48     scanf("%d%d%d",&n,&m,&k);
 49     for (int a=1;a<=m;a++)
 50     {
 51         int s,e;
 52         scanf("%d%d",&s,&e);
 53         char c='!';
 54         bool find=false;
 55         while (~scanf("%c",&c))
 56         {
 57             if (c=='\n' || c=='\r') break;
 58             if ((c>='A' && c<='Z') || (c>='a' && c<='z'))
 59             {
 60                 find=true;
 61                 if (c>='A' && c<='Z') add_edge(s,e,c);
 62                 else add_edge2(s,e,c);
 63                 break;
 64             }
 65         }
 66         if (!find) c='!',add_edge(s,e,c);
 67     }
 68     for (int a=1;a<=n;a++)
 69         f[a][a][0]=1,g[a][a][0]=1;
 70     for (int a=1;a<=cnt1;a++)
 71         for (int b=1;b<=cnt2;b++)
 72             if (e1[a]==s2[b] && t1[a]==t2[b]) g[s1[a]][e2[b]][2]++;
 73     for (int a=1;a<=k;a++)
 74     {
 75         for (int b=1;b<=n;b++)
 76             for (int c=1;c<=n;c++)
 77             {
 78                 int &x=f[b][c][a];
 79                 for (edge *e=v[b];e;e=e->next)
 80                     if (e->v=='!')
 81                     {
 82                         x+=f[e->e][c][a-1];
 83                         if (x>=mo) x-=mo;
 84                     }
 85                 for (int d=1;d<=n;d++)
 86                     for (int e=2;e<=a;e++)
 87                         x=(x+g[b][d][e]*f[d][c][a-e])%mo;
 88             }
 89         if (a+2<=k)
 90         {
 91             for (int b=1;b<=cnt1;b++)
 92                 if (t1[b])
 93                     for (int c=1;c<=cnt2;c++)
 94                         if (t1[b]==t2[c]) 
 95                         {
 96                             int &x=g[s1[b]][e2[c]][a+2];
 97                             x+=f[e1[b]][s2[c]][a];
 98                             if (x>=mo) x-=mo;
 99                         }
100         }
101     }
102     for (int a=1;a<=cnt1;a++)
103         if (t1[a]) h[s1[a]][e1[a]][1]++;
104     for (int a=2;a<=k;a++)
105         for (int b=1;b<=n;b++)
106             for (int c=1;c<=n;c++)
107             {
108                 int &x=h[b][c][a];
109                 for (edge *e=v[b];e;e=e->next)
110                     if (e->v!='!')
111                     {
112                         x+=h[e->e][c][a-1]+f[e->e][c][a-1];
113                         if (x>=mo) x-=mo;
114                         if (x>=mo) x-=mo;
115                     }
116                     else 
117                     {
118                         x+=h[e->e][c][a-1];
119                         if (x>=mo) x-=mo;
120                     }
121                 for (int d=1;d<=n;d++)
122                     for (int e=2;e<a;e++)
123                         x=(x+g[b][d][e]*h[d][c][a-e])%mo;
124             }
125     int ans=0;
126     for (int a=0;a<=k;a++)
127         ans=(ans+f[1][n][a]+h[1][n][a])%mo;
128     printf("%d\n",ans);
129 
130     return 0;
131 }

 

第三题:

 

可以很容易发现题目就是问一条直线Y=kX+b中的b最大值,那么考虑这个问题实际上就是在一个上凸壳中询问一条与y轴截距最大的直线,那么每次二分答案就可以解决了。

 

View Code
 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 
 5 using namespace std;
 6 
 7 #ifdef unix
 8 #define LL "%lld"
 9 #else
10 #define LL "%I64d"
11 #endif
12 
13 const int maxn=100010;
14 
15 int n,m,size;
16 
17 long long x[maxn],y[maxn],sum[maxn],f[maxn];
18 
19 long long cross(long long x1,long long y1,long long x2,long long y2)
20 {
21     return x1*y2-x2*y1;
22 }
23 
24 void get_hull()
25 {
26     x[1]=0;y[1]=sum[1];
27     x[2]=sum[1];y[2]=sum[2];
28     size=2;
29     for (int a=3;a<=n;a++)
30     {
31         long long xx=sum[a-1],yy=sum[a];
32         while (size && cross(xx-x[size],yy-y[size],xx-x[size-1],yy-y[size-1])<=0)
33             size--;
34         size++;
35         x[size]=xx;
36         y[size]=yy;
37     }
38 }
39 
40 int main()
41 {
42     
43     scanf("%d%d",&n,&m);
44     for (int a=1;a<=n;a++)
45         scanf(LL,&sum[a]),sum[a]+=sum[a-1];
46     for (int a=1;a<=m;a++)
47         scanf(LL,&f[a]);
48     get_hull();
49     long long ans=0;
50     for (int a=2;a<=m;a++)
51     {
52         if (size==1) ans+=f[a-1]*y[1];
53         else
54         {
55             if (cross(f[a-1],f[a],x[2]-x[1],y[2]-y[1])<=0) ans+=f[a-1]*y[1]-f[a]*x[1];
56             else
57             {
58                 if (cross(x[size]-x[size-1],y[size]-y[size-1],f[a-1],f[a])<=0) ans+=f[a-1]*y[size]-f[a]*x[size];
59                 else
60                 {
61                     int l=2,r=size+1;
62                     while (l+1!=r)
63                     {
64                         int m=(l+r)>>1;
65                         if (cross(x[m]-x[m-1],y[m]-y[m-1],f[a-1],f[a])<=0) l=m;
66                         else r=m;
67                     }
68                     ans+=f[a-1]*y[l]-f[a]*x[l];
69                 }
70             }
71         }
72     }
73     ans+=sum[n]*f[m];
74     printf(LL "\n",ans);
75 
76     return 0;
77 }

 

Day 4:

 

第一题:

 

这题太囧了………………其实就是要求动态维护重心………………

 

考虑每次合并两颗子树的时候新的重心一定在两颗树的原来之间的路径上,那么我们可以用LCT将这两个点到他们的LCA的路径搞出来,然后我们中途动态维护一些值就可以做了,这种做法可以去看fhq的博客。

 

我用的是一种囧到不能再囧的方法…………我们先把所有询问离线,然后在预处理时只考虑加边操作,每次进行启发式合并,将小树的dfs序并到大树的dfs序的后面去,这样可以在O(nlogn)的时间内将所有时刻对应的不同的dfs序给搞出来。然后再来做询问,考虑每次需要维护重心,而重心只会在加边的时候改变。这个时候我们暴力修改小树的倍增父亲的值,然后找出原来两个重心的LCA,然后就相当于是在这两个链上找到一个重心。考虑我们从大树的重心向上移,每移一次我们需要知道所有点到这两个点的距离总和,相当于只要我们知道这棵子树的大小就可以算出这个差量了。由于我们之前维护了一个任意时刻的dfs序,所以我们直接使用树状数组维护每一个dfs序,这样就可以询问一颗子树的当前大小,从而解决这个增量的问题。然后可以发现这个是有一定的单调性的,所以利用那个维护的倍增父亲的值就可以顺利解决了。

 

View Code
  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<vector>
  5 
  6 using namespace std;
  7 
  8 const int maxn=100010;
  9 const int maxq=200010;
 10 
 11 #define lb(a) ((a)&(-(a)))
 12 
 13 int n,m,en,depth[maxn],q[maxq][3],size[maxn],root[maxn],f[maxn][20],mid[maxn],id[maxn],idx,p[maxn],belong[maxq+maxn],tmp,ans;
 14 
 15 char s[10];
 16 
 17 struct rec
 18 {
 19     int id,pos;
 20     rec(){}
 21     rec(int a,int b)
 22     {
 23         id=a;pos=b;
 24     }
 25 };
 26 
 27 vector<rec> into[maxn],outto[maxn];
 28 
 29 vector<int> tree[maxq];
 30 
 31 struct edge
 32 {
 33     int e;
 34     edge *next;
 35 }*v[maxn],ed[maxn<<1];
 36 
 37 void add_edge(int s,int e)
 38 {
 39     en++;
 40     ed[en].next=v[s];v[s]=ed+en;v[s]->e=e;
 41 }
 42 
 43 void add(int id,int p)
 44 {
 45     while (p<(int)tree[id].size())
 46     {
 47         tree[id][p]++;
 48         p+=lb(p);
 49     }
 50 }
 51 
 52 int query(int id,int p)
 53 {
 54     int ans=0;
 55     while (p)
 56     {
 57         ans+=tree[id][p];
 58         p-=lb(p);
 59     }
 60     return ans;
 61 }
 62 
 63 void build(int now,int fa,int id)
 64 {
 65     if (fa==0) tree[id].push_back(0);
 66     tree[id].push_back(0);
 67     into[now].push_back(rec(id,tree[id].size()-1));
 68     for (edge *e=v[now];e;e=e->next)
 69         if (e->e!=fa) build(e->e,now,id);
 70     tree[id].push_back(0);
 71     outto[now].push_back(rec(id,tree[id].size()-1));
 72 }
 73 
 74 void change(int now,int fa,int rt,bool dep)
 75 {
 76     root[now]=rt;
 77     if (dep)
 78     {
 79         depth[now]=depth[fa]+1;
 80         memset(f[now],0,sizeof(f[now]));
 81         f[now][0]=fa;
 82         int x=0,nowp=fa;
 83         while (f[nowp][x])
 84         {
 85             f[now][x+1]=f[nowp][x];
 86             nowp=f[nowp][x];
 87             x++;
 88         }
 89     }
 90     for (edge *e=v[now];e;e=e->next)
 91         if (e->e!=fa) change(e->e,now,rt,dep);
 92 }
 93 
 94 void prepare()
 95 {
 96     for (int a=1;a<=n;a++)
 97     {
 98         size[a]=depth[a]=1;
 99         root[a]=id[a]=a;
100     }
101     idx=n;
102     for (int a=1;a<=m;a++)
103         if (q[a][0]==1)
104         {
105             int p1=q[a][1],p2=q[a][2];
106             if (size[root[p1]]<size[root[p2]]) swap(p1,p2);
107             if (size[root[p1]]==size[root[p2]] && p1>p2) swap(p1,p2);
108             int r1=root[p1],r2=root[p2];
109             size[r1]+=size[r2];
110             build(r2,0,id[r2]);
111             add_edge(p1,p2);
112             add_edge(p2,p1);
113             change(p2,p1,r1,false);
114             idx++;
115             belong[id[r1]]=idx;
116             id[r1]=idx;
117         }
118     for (int a=1;a<=n;a++)
119         if (root[a]==a) build(a,0,id[a]);
120     for (int a=idx;a>=1;a--)
121         if (belong[a]==0) belong[a]=a;
122         else belong[a]=belong[belong[a]];
123 }
124 
125 void insert(int now,int id)
126 {
127     while (into[now][p[now]].id!=id)
128         p[now]++;
129     add(id,into[now][p[now]].pos);
130 }
131 
132 void insert(int now,int fa,int id)
133 {
134     insert(now,id);
135     for (edge *e=v[now];e;e=e->next)
136         if (e->e!=fa) insert(e->e,now,id);
137 }
138 
139 int get_lca(int p1,int p2)
140 {
141     if (depth[p1]<depth[p2]) swap(p1,p2);
142     int delta=depth[p1]-depth[p2],x=0;
143     while (delta)
144     {
145         if (delta&1) p1=f[p1][x];
146         x++;
147         delta>>=1;
148     }
149     x=0;
150     while (p1!=p2)
151     {
152         if (!x || f[p1][x]!=f[p2][x])
153         {
154             p1=f[p1][x];
155             p2=f[p2][x];
156             x++;
157         }
158         else x--;
159     }
160     return p1;
161 }
162 
163 int get_sum(int now,int id)
164 {
165     int ans=0;
166     while (outto[now][p[now]].id!=id)
167         p[now]++;
168     ans=query(id,outto[now][p[now]].pos);
169     while (into[now][p[now]].id!=id)
170         p[now]++;
171     ans-=query(id,into[now][p[now]].pos-1);
172     return ans;
173 }
174 
175 int get_sum2(int now,int id)
176 {
177     int ans=0;
178     int l=-1,r=outto[now].size()-1;
179     while (l+1!=r)
180     {
181         int m=(l+r)>>1;
182         if (outto[now][m].id>=id) r=m;
183         else l=m;
184     }
185     ans=query(id,outto[now][r].pos);
186     l=-1,r=into[now].size()-1;
187     while (l+1!=r)
188     {
189         int m=(l+r)>>1;
190         if (into[now][m].id>=id) r=m;
191         else l=m;
192     }
193     ans-=query(id,into[now][r].pos-1);
194     return ans;
195 }
196 
197 int get_next(int p1,int p2)
198 {
199     int delta=depth[p2]-depth[p1]-1;
200     int x=0;
201     if (delta<0) return -1;
202     while (delta)
203     {
204         if (delta&1) p2=f[p2][x];
205         x++;
206         delta>>=1;
207     }
208     return p2;
209 }
210 
211 void get_change(int &nowmid,int idx,int next)
212 {
213     int p=nowmid;
214     int ep=f[nowmid][0];
215     int delta;
216     if (ep)
217     {
218         delta=size[root[nowmid]]-2*get_sum2(nowmid,belong[idx]);
219         if (delta==0 && ep<p) p=ep;
220     }
221     if (next!=-1)
222     {
223         delta=size[root[nowmid]]-2*get_sum2(next,belong[idx]);
224         if (delta==0 && next<p) p=next;
225     }
226     nowmid=p;
227 }
228 
229 int dfs(int now,int fa)
230 {
231     int nowsum=1;
232     for (edge *e=v[now];e;e=e->next)
233         if (e->e!=fa) nowsum+=dfs(e->e,now);
234     tmp+=nowsum;
235     return nowsum;
236 }
237 
238 void solve()
239 {
240     en=0;
241     for (int a=1;a<=n;a++)
242     {
243         size[a]=1;
244         root[a]=mid[a]=id[a]=a;
245         insert(a,belong[a]);
246         v[a]=NULL;
247         ans^=a;
248     }
249     idx=n;
250     for (int a=1;a<=m;a++)
251         if (q[a][0]==2) printf("%d\n",ans);
252         else
253         {
254             if (q[a][0]==3) printf("%d\n",mid[root[q[a][1]]]);
255             else
256             {
257                 int p1=q[a][1],p2=q[a][2];
258                 if (size[root[p1]]<size[root[p2]]) swap(p1,p2);
259                 if (size[root[p1]]==size[root[p2]] && p1>p2) swap(p1,p2);
260                 int r1=root[p1],r2=root[p2];
261                 int ans1=mid[r1],ans2=mid[r2];
262                 size[r1]+=size[r2];
263                 add_edge(p1,p2);
264                 add_edge(p2,p1);
265                 change(p2,p1,r1,true);
266                 int lca=get_lca(mid[r1],p1);
267                 idx++;
268                 id[r1]=idx;
269                 insert(p2,p1,belong[idx]);
270                 tmp=0;
271                 dfs(p2,p1);
272                 int nowmid=mid[r1];
273                 while (nowmid!=lca)
274                 {
275                     int nowsum=get_sum(nowmid,belong[idx]);
276                     if (size[r1]>(nowsum<<1)) nowmid=f[nowmid][0];
277                     else break;
278                 }
279                 if (nowmid!=lca)
280                 {
281                     int next=get_next(nowmid,r1);
282                     get_change(nowmid,idx,next);
283                     mid[r1]=nowmid;
284                     ans^=mid[r1]^ans1^ans2;
285                     continue;
286                 }
287                 int x=0;
288                 nowmid=p1;
289                 while (f[nowmid][x])
290                     x++;
291                 while (x>=0)
292                 {
293                     if (f[nowmid][x])
294                     {
295                         int nowsum=get_sum(f[nowmid][x],belong[idx]);
296                         if (size[r1]>=(nowsum<<1)) nowmid=f[nowmid][x];
297                     }
298                     x--;
299                 }
300                 tmp=2*get_sum(nowmid,belong[idx])-size[r1];
301                 if (tmp<0 && f[nowmid][0]) nowmid=f[nowmid][0];
302                 int next=get_next(nowmid,p1);
303                 get_change(nowmid,idx,next);
304                 mid[r1]=nowmid;
305                 ans^=ans1^ans2^mid[r1];
306             }
307         }
308 }
309 
310 int main()
311 {
312     scanf("%d%d",&n,&m);
313     for (int a=1;a<=m;a++)
314     {
315         scanf("%s",s);
316         if (s[0]=='A') 
317         {
318             q[a][0]=1;
319             scanf("%d%d",&q[a][1],&q[a][2]);
320         }
321         else 
322         {
323             if (s[0]=='X') q[a][0]=2;
324             else 
325             {
326                 q[a][0]=3;
327                 scanf("%d",&q[a][1]);
328             }
329         }
330     }
331     prepare();
332     solve();
333 
334     return 0;
335 }

 

第二题:

 

这个…………网络流应该是很明显的…………问题就是建模吧…………

 

建模方式如下:

 

1、  首先将每个点的va、vb值乘二。

2、  将每条边的ea、eb值加上ec。

3、  将ans记为当前所有的va、vb之和加上每条边的三种权值之和。

4、  从源点向每个点连一条容量为va的边

5、  从每个点向汇点连一条容量为vb的边

6、  对于一条边,将起点和终点之间连一条容量为ea+eb+2*ec的边。

 

那么最后的答案即为(ans-最大流)/2。

 

至于这个模型的正确性,只需要考虑其割集的意义便可以很容易的证明了。(如果有人不懂的话我再把那个囧图画出来吧………………)

 

View Code
  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<algorithm>
  5 
  6 using namespace std;
  7 
  8 #ifdef unix
  9 #define LL "%lld"
 10 #else
 11 #define LL "%I64d"
 12 #endif
 13 
 14 const int maxn=10010*2;
 15 const int maxm=40010*6;
 16 const long long INF=123456789876543ll;
 17 
 18 int n,m,en,s,t;
 19 
 20 long long va[maxn],vb[maxn],ans,depth[maxn],q[maxn];
 21 
 22 struct edge
 23 {
 24     int e;
 25     long long f;
 26     edge *next,*op;
 27 }*v[maxn],ed[maxm];
 28 
 29 void add_edge(int s,int e,long long f)
 30 {
 31     en++;
 32     ed[en].next=v[s];v[s]=ed+en;v[s]->e=e;v[s]->f=f;
 33     en++;
 34     ed[en].next=v[e];v[e]=ed+en;v[e]->e=s;v[e]->f=0;
 35     v[s]->op=v[e];v[e]->op=v[s];
 36 }
 37 
 38 bool bfs()
 39 {
 40     memset(depth,0,sizeof(depth));
 41     depth[s]=1;
 42     int front=1,tail=1;
 43     q[front]=s;
 44     while (front<=tail)
 45     {
 46         int now=q[front];
 47         front++;
 48         for (edge *e=v[now];e;e=e->next)
 49             if (e->f && !depth[e->e])
 50             {
 51                 depth[e->e]=depth[now]+1;
 52                 tail++;
 53                 q[tail]=e->e;
 54             }
 55     }
 56     return depth[t]!=0;
 57 }
 58 
 59 long long dfs(int now,long long cur_flow)
 60 {
 61     if (now==t) return cur_flow;
 62     long long rest=cur_flow;
 63     for (edge *e=v[now];e;e=e->next)
 64         if (e->f && rest && depth[e->e]>depth[now])
 65         {
 66             long long new_flow=dfs(e->e,min(e->f,rest));
 67             e->f-=new_flow;
 68             e->op->f+=new_flow;
 69             rest-=new_flow;
 70         }
 71     if (cur_flow==rest) depth[now]=0;
 72     return cur_flow-rest;
 73 }
 74 
 75 long long dinic()
 76 {
 77     long long ans=0;
 78     while (bfs())
 79         ans+=dfs(s,INF);
 80     return ans;
 81 }
 82 
 83 int main()
 84 {
 85     scanf("%d%d",&n,&m);
 86     for (int a=2;a<n;a++)
 87     {
 88         scanf(LL,&va[a]);
 89         va[a]<<=1;
 90         ans+=va[a];
 91     }
 92     for (int a=2;a<n;a++)
 93     {
 94         scanf(LL,&vb[a]);
 95         vb[a]<<=1;
 96         ans+=vb[a];
 97     }
 98     va[1]=INF;vb[n]=INF;
 99     for (int a=1;a<=m;a++)
100     {
101         int s,e,ea,eb,ec;
102         scanf("%d%d%d%d%d",&s,&e,&ea,&eb,&ec);
103         ans+=(ea+eb+ec)<<1;
104         ea+=ec;
105         eb+=ec;
106         va[s]+=ea;va[e]+=ea;
107         vb[s]+=eb;vb[e]+=eb;
108         add_edge(s,e,ea+eb);
109         add_edge(e,s,ea+eb);
110     }
111     s=0;t=n+1;
112     for (int a=1;a<=n;a++)
113         add_edge(0,a,va[a]);
114     for (int a=1;a<=n;a++)
115         add_edge(a,n+1,vb[a]);
116     printf(LL "\n",(ans-dinic())>>1);
117 
118     return 0;
119 }

 

第三题:

 

这题好像很水的样子啊………………

 

考虑有几行被选了奇数次,那么有多少列被选了奇数次也就确定了,这样一来的话就成了简单的组合计数问题了…………囧………………

 

View Code
  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<algorithm>
  5 
  6 using namespace std;
  7 
  8 #ifdef unix
  9 #define LL "%lld"
 10 #else
 11 #define LL "%I64d"
 12 #endif
 13 
 14 const int maxn=100010;
 15 const int mo=1000000007;
 16 
 17 int n,m,r,c,ans,v0[maxn],v1[maxn],v2[maxn],v3[maxn],v4[maxn];
 18 
 19 long long s;
 20 
 21 int multi(long long a,int b)
 22 {
 23     a*=b;
 24     if (a>=mo) a%=mo;
 25     return (int)a;
 26 }
 27 
 28 void inc(int &a,int b)
 29 {
 30     a+=b;
 31     if (a>=mo) a-=mo;
 32 }
 33 
 34 int mul(int a,int b)
 35 {
 36     int ans=1;
 37     while (b)
 38     {
 39         if (b&1) ans=multi(ans,a);
 40         a=multi(a,a);
 41         b>>=1;
 42     }
 43     return ans;
 44 }
 45 
 46 int main()
 47 {
 48     scanf("%d%d%d%d" LL,&n,&m,&r,&c,&s);
 49     v1[0]=1;
 50     for (int a=1;a<=100000;a++)
 51         v0[a]=mul(a,mo-2);
 52     int tmp=1;
 53     for (int a=0;a<=(r>>1);a++)
 54     {
 55         v1[a]=tmp;
 56         tmp=multi(tmp,multi(a+n,v0[a+1]));
 57     }
 58     tmp=1;
 59     for (int a=0;a<=(c>>1);a++)
 60     {
 61         v2[a]=tmp;
 62         tmp=multi(tmp,multi(a+m,v0[a+1]));
 63     }
 64     tmp=1;
 65     for (int a=0;a<=n;a++)
 66     {
 67         v3[a]=tmp;
 68         tmp=multi(tmp,multi(n-a,v0[a+1]));
 69     }
 70     tmp=1;
 71     for (int a=0;a<=m;a++)
 72     {
 73         v4[a]=tmp;
 74         tmp=multi(tmp,multi(m-a,v0[a+1]));
 75     }
 76     for (int a=r&1;a<=min(n,r);a+=2)
 77         if (a*2!=n)
 78         {
 79             if (((s-(long long)a*m))%(n-a*2)) continue;
 80             int b=(int)((s-(long long)a*m)/(n-a*2));
 81             if (b>c || b<0 || ((c-b)&1)) continue;
 82             int nowans=v3[a];
 83             nowans=multi(nowans,v1[(r-a)>>1]);
 84             nowans=multi(nowans,v4[b]);
 85             nowans=multi(nowans,v2[(c-b)>>1]);
 86             inc(ans,nowans);
 87         }
 88         else
 89         {
 90             if ((long long)a*m!=s) continue;
 91             int nowans=v3[a];
 92             nowans=multi(nowans,v1[(r-a)>>1]);
 93             int cnt=0;
 94             for (int b=(c&1);b<=min(r,c);b+=2)
 95                 inc(cnt,multi(v4[b],v2[(c-b)>>1]));
 96             inc(ans,multi(ans,cnt));
 97         }
 98     printf("%d\n",ans);
 99 
100     return 0;
101 }

 

Day 5:

 

这天的题囧爆了………………

 

第一题:

 

由于有第一天第三题…………所以这题就太水了吧…………找出两个数列的循环节然后暴力乱搞就行了吧…………

 

View Code
  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 
  5 using namespace std;
  6 
  7 #ifdef unix
  8 #define LL "%lld"
  9 #else
 10 #define LL "%I64d"
 11 #endif
 12 
 13 const int maxn=200;
 14 const long long mo=1000000007;
 15 const long long mo2=mo*2+2;
 16 const long long mo3=mo2*3;
 17 
 18 char s[maxn];
 19 
 20 struct matrix
 21 {
 22     long long z[3][3];
 23     matrix()
 24     {
 25         memset(z,0,sizeof(z));
 26     }
 27     matrix operator*(const matrix &a)const
 28     {
 29         matrix ans;
 30         for (int b=1;b<=2;b++)
 31             for (int c=1;c<=2;c++)
 32                 for (int d=1;d<=2;d++)
 33                     ans.z[b][c]=(ans.z[b][c]+z[b][d]*a.z[d][c]%mo)%mo;
 34         return ans;
 35     }
 36     matrix operator+(const matrix &a)const
 37     {
 38         matrix ans;
 39         for (int b=1;b<=2;b++)
 40             for (int c=1;c<=2;c++)
 41                 for (int d=1;d<=2;d++)
 42                     ans.z[b][c]=(ans.z[b][c]+z[b][d]*a.z[d][c]%mo2)%mo2;
 43         return ans;
 44     }
 45 }m1,m2;
 46 
 47 struct bign
 48 {
 49     int z[maxn],l;
 50     void init()
 51     {
 52         memset(z,0,sizeof(z));
 53         scanf("%s",s+1);
 54         l=strlen(s+1);
 55         for (int a=1;a<=l;a++)
 56             z[a]=s[l-a+1]-'0';
 57     }
 58     long long operator%(const long long &a)const
 59     {
 60         long long b=0;
 61         for (int c=l;c>=1;c--)
 62             b=(b*10+z[c])%a;
 63         return b;
 64     }
 65 }z;
 66 
 67 long long get(long long v)
 68 {
 69     if (v==0) return 0;
 70     m1.z[1][1]=0;
 71     m1.z[1][2]=1;
 72     m2.z[1][1]=0;
 73     m2.z[1][2]=m2.z[2][1]=m2.z[2][2]=1;
 74     while (v)
 75     {
 76         if (v&1) m1=m1*m2;
 77         m2=m2*m2;
 78         v>>=1;
 79     }
 80     return m1.z[1][1];
 81 }
 82 
 83 long long get1(long long v)
 84 {
 85     if (v==0) return 0;
 86     m1.z[1][1]=0;
 87     m1.z[1][2]=1;
 88     m2.z[1][1]=0;
 89     m2.z[1][2]=m2.z[2][1]=m2.z[2][2]=1;
 90     while (v)
 91     {
 92         if (v&1) m1=m1+m2;
 93         m2=m2+m2;
 94         v>>=1;
 95     }
 96     return m1.z[1][1];
 97 }
 98 
 99 int main()
100 {
101     int t;
102     scanf("%d",&t);
103     for (int a=1;a<=t;a++)
104     {
105         z.init();
106         long long v1=z % mo3;
107         v1=get1(v1);
108         printf(LL "\n",get(v1));
109     }
110 
111     return 0;
112 }

 

第二题:

 

题解上说暴力打张表出来…………囧…………

 

View Code
 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 
 5 using namespace std;
 6 
 7 char s[2600]="3141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920962829254091715364367892590360011330530548820466521384146951941511609433057270365759591953092186117381932611793105118548074462379962749567351885752724891227938183011949129833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901224953430146549585371050792279689258923542019956112129021960864034418159813629774771309960518707211349999998372978049951059731732816096318595024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909216420198938095257201065485863278";
 8 
 9 int n;
10 
11 int main()
12 {
13     scanf("%d",&n);
14     for (int a=0;a<n;a++)
15         printf("%c",s[a]);
16     printf("\n");
17 
18     return 0;
19 }

 

第三题:

 

考虑10^10=2^10*5^10,那么只要分别搞出答案对这两个数的余数然后用中国剩余定理就搞定了(其实这里可以暴力………………)

 

我们这里只考虑C(n,m) mod 2^10的情况,等价于n!/m!/(n-m)! mod 2^10,很明显我们在算的时候需要把2这个约数单独拿出来考虑,那么问题变成了设n!=x*2^y,x是一个奇数,求x mod 2^10,我们先把n=1024的情况暴力出来之后,然后我们发现不考虑偶数的话每1024个数的情况都是一样的,这个就可以很快的求出来了。然后我们考虑偶数,首先把每个偶数都除以二,我们发现这个问题就转化成了一个规模更小的原问题,那么递归处理下去就可以了。

 

View Code
 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 
 5 using namespace std;
 6 
 7 #ifdef unix
 8 #define LL "%lld"
 9 #else
10 #define LL "%I64d"
11 #endif
12 
13 #ifdef unix
14 #define LX "%010lld"
15 #else
16 #define LX "%010I64d"
17 #endif
18 
19 const long long mo=10000000000ll;
20 const long long mo1=1024;
21 const long long mo2=9765625;
22 
23 long long n,m,v[mo2];
24 
25 long long get(long long a,int b)
26 {
27     long long ans=0;
28     while (a)
29     {
30         ans+=a/b;
31         a/=b;
32     }
33     return ans;
34 }
35 
36 long long mul(long long a,long long b,long long mo)
37 {
38     long long ans=1;
39     while (b)
40     {
41         if (b&1) ans=ans*a%mo;
42         a=a*a%mo;
43         b>>=1;
44     }
45     return ans;
46 }
47 
48 long long fac(long long n,long long div,long long mo)
49 {
50     long long nowans=1;
51     if (n>=div) nowans=fac(n/div,div,mo);
52     return nowans*(mul(v[mo-1],n/mo,mo)*v[n%mo]%mo)%mo;
53 }
54 
55 long long calc(long long n,long long m,long long div)
56 {
57     int sum;
58     if ((sum=get(n,div)-get(m,div)-get(n-m,div))>=10) return 0;
59     long long mo;
60     if (div==2) mo=mo1;
61     else mo=mo2;
62     v[0]=1;
63     for (int a=1;a<mo;a++)
64         v[a]=v[a-1]*(a%div?a:1)%mo;
65     return fac(n,div,mo)*mul(fac(m,div,mo)*fac(n-m,div,mo)%mo,mo/div*(div-1)-1,mo)%mo*mul(div,sum,mo)%mo;
66 }
67 
68 
69 int main()
70 {
71 
72     scanf(LL LL,&n,&m);
73     if (n<m)
74     {
75         printf("0000000000\n");
76         return 0;
77     }
78     long long v1=calc(n,m,2);
79     long long v2=calc(n,m,5);
80     while (v2%mo1!=v1)
81         v2+=mo2;
82     printf(LX "\n",v2);
83 
84     return 0;
85 }

 

Day 6:

 

第一题:

 

我们把这个问题离线来做,我们对B树的每一个点从它自己到根的字符串按照字典序排个序。

然后开始处理询问,分两种情况:

 

1、  对A树添加一个节点:

 

考虑新节点的父亲,如果我们对新节点的父亲在B那个已经排序好的数组里记录了一个可匹配的区间,那么新的节点在那个数组中能够匹配的区间一定是被父亲的区间所包含的,且我们在找这个区间时只需要匹配新加入的这个字母。于是我们在这个区间里二分上下界得到一个新的区间,那么就处理出了新节点所对应的一个区间。然后这种操作对答案的影响便是这个区间内有多少个B的串已被加入,这个可以在没次加入一个B中的结点时用树状数组维护即可。

 

2、  对B树添加一个结点:

 

考虑这种操作对答案的影响,它能带来的影响就是以前有多少个A树中的结点所对应的区间包含了它,那么这个也可以用一个树状数组维护即可。

 

View Code
  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<algorithm>
  5 
  6 using namespace std;
  7 
  8 #ifdef unix
  9 #define LL "%lld"
 10 #else
 11 #define LL "%I64d"
 12 #endif
 13 
 14 #define lb(p) (p)&(-(p))
 15 
 16 const int maxn=100010;
 17 const unsigned long long base=10003;
 18 
 19 int n,q[maxn][3],z1[maxn],z2[maxn],f[maxn][20],fe[maxn],cnt2,size1,size2,sa[maxn],rank[maxn],depth1[maxn],depth2[maxn];
 20 
 21 long long ans;
 22 
 23 unsigned long long bit[maxn],h[maxn];
 24 
 25 pair<int,int> range[maxn];
 26 
 27 void change(int *z,int p,int delta)
 28 {
 29     while (p<=cnt2)
 30     {
 31         z[p]+=delta;
 32         p+=lb(p);
 33     }
 34 }
 35 
 36 int query(int *z,int p)
 37 {
 38     int ans=0;
 39     while (p)
 40     {
 41         ans+=z[p];
 42         p-=lb(p);
 43     }
 44     return ans;
 45 }
 46 
 47 bool cmp(int a,int b)
 48 {
 49     int x=0;
 50     while ((1<<x)<depth2[a] && (1<<x)<depth2[b])
 51         x++;
 52     for (x--;x>=0;x--)
 53     {
 54         unsigned long long h1=h[a]-h[f[a][x]]*bit[1<<x];
 55         unsigned long long h2=h[b]-h[f[b][x]]*bit[1<<x];
 56         if (h1==h2) a=f[a][x],b=f[b][x];
 57     }
 58     return fe[a]<fe[b];
 59 }
 60 
 61 int up(int p,int s)
 62 {
 63     int x=0;
 64     while (s)
 65     {
 66         if (s&1) p=f[p][x];
 67         s>>=1;
 68         x++;
 69     }
 70     return p;
 71 }
 72 
 73 int main()
 74 {
 75 
 76     scanf("%d",&n);
 77     bit[0]=1;
 78     for (int a=1;a<=n;a++)
 79         bit[a]=bit[a-1]*base;
 80     depth1[1]=depth2[1]=1;
 81     cnt2=1;
 82     for (int a=1;a<=n;a++)
 83     {
 84         int t,v;
 85         char s[2],c;
 86         scanf("%d%d%s",&t,&v,s);
 87         c=s[0];
 88         q[a][0]=t;q[a][1]=v;q[a][2]=c;
 89         if (t==2)
 90         {
 91             cnt2++;
 92             depth2[cnt2]=depth2[v]+1;
 93             fe[cnt2]=c;
 94             h[cnt2]=h[v]*base+c-'a'+1;
 95             f[cnt2][0]=v;
 96             int x=0;
 97             while (f[v][x])
 98             {
 99                 f[cnt2][x+1]=f[v][x];
100                 v=f[v][x];
101                 x++;
102             }
103         }
104     }
105     for (int a=1;a<=cnt2;a++)
106         sa[a]=a;
107     sort(sa+1,sa+cnt2+1,cmp);
108     for (int a=1;a<=cnt2;a++)
109         rank[sa[a]]=a;
110     size1=size2=1;
111     range[1]=make_pair(1,cnt2+1);
112     for (int a=1;a<=n;a++)
113     {
114         if (q[a][0]==1)
115         {
116             size1++;
117             depth1[size1]=depth1[q[a][1]]+1;
118             if (range[q[a][1]].first!=-1)
119             {
120                 int lower=range[q[a][1]].first,upper=range[q[a][1]].second-1;
121                 int l=lower,r=upper;
122                 while (l<=r)
123                 {
124                     int m=(l+r)>>1;
125                     if (fe[up(sa[m],depth1[size1]-2)]<q[a][2]) l=m+1;
126                     else r=m-1;
127                 }
128                 int new_lower=l;
129                 l=lower,r=upper;
130                 while (l<=r)
131                 {
132                     int m=(l+r)>>1;
133                     if (fe[up(sa[m],depth1[size1]-2)]>q[a][2]) r=m-1;
134                     else l=m+1;
135                 }
136                 int new_upper=r+1;
137                 if (new_lower>=new_upper) range[size1]=make_pair(-1,-1);
138                 else
139                 {
140                     ans+=query(z2,new_upper-1)-query(z2,new_lower-1);
141                     change(z1,new_lower,1);
142                     change(z1,new_upper,-1);
143                     range[size1]=make_pair(new_lower,new_upper);
144                 }
145             }
146             else range[size1]=make_pair(-1,-1);
147         }
148         else
149         {
150             size2++;
151             change(z2,rank[size2],1);
152             ans+=query(z1,rank[size2]);
153         }
154         printf(LL "\n",ans+size2);
155     }
156 
157     return 0;
158 }

 

第二题:

 

最暴力的dp很好做…………但是会T…………正确的做法要用stirling数进行优化…………但是我不会………………

 

(暂无)

 

第三题:

 

这题更不会了…………只知道是树链剖分套动态树…………以后有时间的时候再来说这道题吧………………

 

(暂无)

 

Day 7:

 

第一题:

 

这题很水,我们设定一个参数t,将度数大于t的设为大点,将剩下的点设为小点。然后我们对大点小点分开做,每次采用不同的方法暴力就行了。

 

View Code
  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<cmath>
  5 #include<algorithm>
  6 
  7 using namespace std;
  8 
  9 #ifdef unix
 10 #define LL "%lld"
 11 #else
 12 #define LL "%I64d"
 13 #endif
 14 
 15 const int maxn=100010;
 16 const int maxm=100010;
 17 
 18 int n,m,q,en,l,bigp[maxn],col[maxn],in[maxn];
 19 
 20 long long sum[2][2],cost[maxn][2];
 21 
 22 bool tag[maxn];
 23 
 24 char s[8];
 25 
 26 struct edge
 27 {
 28     int e;
 29     long long d;
 30     edge *next;
 31 }*v[maxn],ed[maxm<<1];
 32 
 33 struct edg
 34 {
 35     int s,e;
 36     long long d;
 37     bool operator==(const edg &a)const
 38     {
 39         return s==a.s && e==a.e;
 40     }
 41     bool operator<(const edg &a)const
 42     {
 43         if (s==a.s) return e<a.e;
 44         else return s<a.s;
 45     }
 46 }e[maxm];
 47 
 48 void add_edge(int s,int e,long long d)
 49 {
 50     en++;
 51     ed[en].next=v[s];v[s]=ed+en;v[s]->e=e;v[s]->d=d;
 52 }
 53 
 54 int main()
 55 {
 56     scanf("%d%d",&n,&m);
 57     for (int a=1;a<=n;a++)
 58         scanf("%d",&col[a]);
 59     for (int a=1;a<=m;a++)
 60     {
 61         scanf("%d%d" LL,&e[a].s,&e[a].e,&e[a].d);
 62         if (e[a].s>e[a].e) swap(e[a].s,e[a].e);
 63         if (e[a].s==0) printf("%d\n",a);
 64     }
 65     sort(e+1,e+m+1);
 66     int last=1;
 67     for (int a=2;a<=m;a++)
 68         if (e[a]==e[last]) e[last].d+=e[a].d,tag[a]=true;
 69         else last=a;
 70     for (int a=1;a<=m;a++)
 71         if (!tag[a]) in[e[a].s]++,in[e[a].e]++;
 72     int maxsize=(int)exp(log(n)*2/3);
 73     //printf("%d\n",maxsize);
 74     for (int a=1;a<=m;a++)
 75         if (!tag[a])
 76         {
 77     //        printf("%d %d %I64d\n",e[a].s,e[a].e,e[a].d);
 78             if (in[e[a].s]>maxsize)
 79             {
 80                 add_edge(e[a].e,e[a].s,e[a].d);
 81                 if (in[e[a].e]>maxsize) 
 82                 {
 83                     add_edge(e[a].s,e[a].e,e[a].d);
 84                     sum[min(col[e[a].s],col[e[a].e])][max(col[e[a].s],col[e[a].e])]+=e[a].d;
 85                 }
 86                 else cost[e[a].s][col[e[a].e]]+=e[a].d;
 87             }
 88             else
 89             {
 90                 add_edge(e[a].s,e[a].e,e[a].d);
 91                 if (in[e[a].e]>maxsize) cost[e[a].e][col[e[a].s]]+=e[a].d;
 92                 else
 93                 {
 94                     add_edge(e[a].e,e[a].s,e[a].d);
 95                     sum[min(col[e[a].s],col[e[a].e])][max(col[e[a].s],col[e[a].e])]+=e[a].d;
 96                 }
 97             }
 98         }
 99     for (int a=1;a<=n;a++)
100         if (in[a]>maxsize)
101         {
102             l++;
103             bigp[l]=a;
104         }
105     //printf("%I64d %I64d %I64d\n",sum[0][0],sum[0][1],sum[1][1]);
106     //for (int a=1;a<=n;a++)
107     //    printf("%I64d %I64d\n",cost[a][0],cost[a][1]);
108     scanf("%d",&q);
109     for (int a=1;a<=q;a++)
110     {
111         scanf("%s",s);
112         if (s[0]=='A')
113         {
114             int c1,c2;
115             scanf("%d%d",&c1,&c2);
116             long long ans=sum[min(c1,c2)][max(c1,c2)];
117             for (int b=1;b<=l;b++)
118             {
119                 int newc=c1+c2-col[bigp[b]];
120                 if (newc==0 || newc==1) ans+=cost[bigp[b]][newc];
121             }
122             printf(LL "\n",ans);
123         }
124         else
125         {
126             int p;
127             scanf("%d",&p);
128             if (in[p]>maxsize)
129             {
130                 for (edge *e=v[p];e;e=e->next)
131                 {
132                     sum[min(col[p],col[e->e])][max(col[p],col[e->e])]-=e->d;
133                     sum[min(col[p]^1,col[e->e])][max(col[p]^1,col[e->e])]+=e->d;
134                 }
135             }
136             else
137             {
138                 for (edge *e=v[p];e;e=e->next)
139                     if (in[e->e]>maxsize)
140                     {
141                         cost[e->e][col[p]]-=e->d;
142                         cost[e->e][col[p]^1]+=e->d;
143                     }
144                     else
145                     {
146                         sum[min(col[p],col[e->e])][max(col[p],col[e->e])]-=e->d;
147                         sum[min(col[p]^1,col[e->e])][max(col[p]^1,col[e->e])]+=e->d;
148                     }
149             }
150             col[p]^=1;
151         }
152     }
153 
154     return 0;
155 }

 

第二题:

 

首先解决周长为n的三角形个数有多少,用f(n)表示,考虑用a、b、c表示三条边并且有a<=b<=c,那么考虑以下两种情况:

 

1、b=c,那么这个时候a+b>c,可以直接算出答案。

2、b<c,那么这个时候一定有a+b>=c+1,所以可以利用f(n-1)的值推过来,在算一下a+b=c+1的情况就行了。

 

然后考虑用g(n)表示周长为n且三边gcd为1的三角形个数,那么考虑排除gcd不为1的情况,这个只需要枚举其gcd为多少然后减去相应的值即可。

 

然后考虑我们需要算出相似的组数,那么考虑所有的相似三角形一定都是基于一个周长然后乘上了某个值,那么我们只需要枚举这个基础周长,然后利用组合公式算一算就行了。

 

View Code
 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<algorithm>
 5 
 6 using namespace std;
 7 
 8 const int maxn=5000010;
 9 const int mo=1000000007;
10 
11 int n,cnt,f[maxn],er[maxn],divisor[maxn];
12 
13 #define inc(a,b) a+=b,(a>=mo ? a-=mo : 0)
14 
15 int main()
16 {
17     scanf("%d",&n);
18     for (int a=2;a<=n;a++)
19         f[a]=f[a-2],inc(f[a],a/3-a/4);
20     for (int a=1;a*a<=n;a++)
21         if (n % a==0)
22         {
23             cnt++;
24             divisor[cnt]=a;
25             if (a*a!=n)
26             {
27                 cnt++;
28                 divisor[cnt]=n/a;
29             }
30         }
31     sort(divisor+1,divisor+cnt+1);
32     for (int a=1;a<=cnt;a++)
33         for (int b=1;b<a;b++)
34             if (divisor[a] % divisor[b]==0) inc(f[divisor[a]],mo-f[divisor[b]]);
35     er[0]=1;
36     for (int a=1;a<=n;a++)
37         er[a]=er[a-1],inc(er[a],er[a-1]);
38     int ans=0;
39     for (int a=1;a<=cnt;a++)
40         inc(ans,(long long)f[divisor[a]]*er[n/divisor[a]-1]%mo);
41     printf("%d\n",ans);
42 
43     return 0;
44 }

 

第三题:

 

此题即为暴力。

 

View Code
 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 
 5 using namespace std;
 6 
 7 long long n;
 8 
 9 #ifdef unix
10 #define LL "%lld"
11 #else
12 #define LL "%I64d"
13 #endif
14 
15 int main()
16 {
17 
18     scanf(LL,&n);
19     long long ans=0,tmp=0;
20     for (long long a=1,v;a*a<=(v=n/a);a++,ans++)
21         for (long long b=a+1;b*b<=v;b++)
22             tmp+=n/(a*b)-b;
23     ans+=tmp*6;
24     tmp=0;
25     for (long long a=1,v;(v=a*a)<=n;a++)
26     {
27         tmp+=n/v;
28         if (a*a<=n/a) tmp--;
29     }
30     ans+=tmp*3;
31     printf(LL "\n",ans);
32 
33     return 0;
34 }

 

Day 8:

 

第一题:

 

这题是大水题啊,推一下然后把矩阵搞出来然后快速幂就行了。注意如果推出来的矩阵比较大需要压缩矩阵,不然会T。

 

View Code
 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 
 5 using namespace std;
 6 
 7 #ifdef unix
 8 #define LL "%lld"
 9 #else
10 #define LL "%I64d"
11 #endif
12 
13 #define inc(a,b) (a+=b,(a>=mo ? a-=mo : 0))
14 
15 long long k,A,B,C,D,n,mo;
16 
17 struct matrix
18 {
19     long long z[3][3];
20     matrix()
21     {
22         memset(z,0,sizeof(z));
23     }
24     void init()
25     {
26         memset(z,0,sizeof(z));
27     }
28     matrix operator*(const matrix &a)const
29     {
30         static matrix ans;
31         ans.init();
32         for (int b=1;b<=2;b++)
33             for (int c=1;c<=2;c++)
34                 for (int d=1;d<=2;d++)
35                     inc(ans.z[b][c],z[b][d]*a.z[d][c]%mo);
36         return ans;
37     }
38 }m1,m2;
39 
40 void gedit(long long &v)
41 {
42     v%=mo;
43     if (v<0) v+=mo;
44 }
45 
46 long long mul(long long a,long long b)
47 {
48     long long ans=1;
49     while (b)
50     {
51         if (b & 1) ans=ans*a%mo;
52         a=a*a%mo;
53         b>>=1;
54     }
55     return ans;
56 }
57 
58 int main()
59 {
60     int t;
61     scanf("%d",&t);
62     for (int p=1;p<=t;p++)
63     {
64         scanf(LL LL LL LL LL LL LL,&k,&A,&B,&C,&D,&n,&mo);
65         gedit(k);
66         gedit(A);
67         gedit(B);
68         gedit(C);
69         gedit(D);
70         if (n==0) printf(LL "\n",k);
71         else
72         {
73             n--;
74             m1.init();m2.init();
75             m1.z[1][1]=A;m1.z[1][2]=C;
76             m1.z[2][1]=B;m1.z[2][2]=D;
77             m2=m1;
78             while (n)
79             {
80                 if (n&1) m1=m1*m2;
81                 m2=m2*m2;
82                 n>>=1;
83             }
84             long long up=(m1.z[1][1]*k%mo+m1.z[2][1])%mo;
85             long long down=(m1.z[1][2]*k%mo+m1.z[2][2])%mo;
86             printf(LL "\n",up*mul(down,mo-2)%mo);
87         }
88     }
89 
90     return 0;
91 }

 

第二题:

 

这题比较神,我们从低位向高位进行dp,没做到一位的时候进行一次排序,将这些数按照后k位的大小进行排序。然后我们考虑我们要减去的那个数的后k位在哪个区间,那么这样我们就可以算出减去这个数后会向高位借多少位,那么每次枚举这个区间就行了。感觉这个思路简直太神了。

 

View Code
 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 
 5 using namespace std;
 6 
 7 #ifdef unix
 8 #define LL "%lld"
 9 #else
10 #define LL "%I64d"
11 #endif
12 
13 const int maxn=200010;
14 
15 int n,delta[maxn];
16 
17 long long f[70][maxn],z[maxn],sw[maxn];
18 
19 int main()
20 {
21 
22     scanf("%d",&n);
23     for (int a=1;a<=n;a++)
24         scanf(LL,&z[a]);
25     f[0][0]=1;
26     for (int a=0;a<=63;a++)
27     {
28         int l1=0,l2=0;
29         memset(delta,0,sizeof(delta));
30         for (int b=1;b<=n;b++)
31             if (((z[b]>>a)&1)==0) l2++;
32         for (int b=1;b<=n;b++)
33             if (((z[b]>>a)&1)==0) 
34             {
35                 l1++;
36                 sw[l1]=z[b];
37                 delta[b]=delta[b-1]+1;
38             }
39             else
40             {
41                 l2++;
42                 sw[l2]=z[b];
43                 delta[b]=delta[b-1];
44             }
45         for (int b=1;b<=n;b++)
46             z[b]=sw[b];
47         for (int b=0;b<=n;b++)
48             if (f[a][b])
49             {
50                 if ((((n-delta[n])^b)&1)==0) f[a+1][delta[b]]+=f[a][b];
51                 if ((((n-delta[n])^(n-b))&1)==0) f[a+1][delta[n]+b-delta[b]]+=f[a][b];
52             }
53     }
54     for (int a=2;a<=n;a++)
55         z[0]^=z[a]-z[1];
56     if (z[0]==0) f[64][0]--;
57     printf(LL "\n",f[64][0]);
58 
59     return 0;
60 }

 

第三题:

 

把式子展开之后就可以发现只有一项特别囧的无法维护,考试的时候我就暴力加一点优化结果有80分…………囧…………

 

如果我们把两个矩阵都写成一行的形式,那么我们就可以发现我们要维护的那个东西就是很类似于高精度乘法的一个东西,于是FFT优化即可,但我不会写FFT…………囧………………

 

(暂无)

 

Day 9:

 

第一题:

 

这题是搞笑的吧…………一开始我想用后缀数组加主席树来做…………发现不就是搞笑题吗…………

 

对模式串建一棵trie,然后每个结点上记录有哪些编号的串能够到达这里,看起来这东西很大,其实空间和时间复杂度都是O(n)的,然后对于每一个询问串暴力走就行了。

 

View Code
 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<vector>
 6 
 7 using namespace std;
 8 
 9 const int maxn=100010;
10 
11 int n,m,z[maxn];
12 
13 char s[maxn];
14 
15 struct node
16 {
17     node *next[26];
18     vector<int> id;
19     node()
20     {
21         memset(next,0,sizeof(next));
22     }
23 }*root,*p,wmt[maxn],*wmtwmt=wmt;
24 
25 node *newnode()
26 {
27     return wmtwmt++;
28 }
29 
30 bool cmp(int a,int b)
31 {
32     return z[a]>z[b];
33 }
34 
35 void insert(int idx)
36 {
37     scanf("%s",s);
38     int l=strlen(s);
39     p=root;
40     for (int a=0;a<l;a++)
41     {
42         if (p->next[s[a]-'a']==NULL) p->next[s[a]-'a']=newnode();
43         p=p->next[s[a]-'a'];
44         if (!p->id.size() || p->id.back()!=idx) p->id.push_back(idx);
45     }
46 }
47 
48 void dfs(node *p)
49 {
50     sort(p->id.begin(),p->id.end(),cmp);
51     for (int a=0;a<26;a++)
52         if (p->next[a]) dfs(p->next[a]);
53 }
54 
55 void query()
56 {
57     int k;
58     scanf("%d%s",&k,s);
59     int l=strlen(s);
60     p=root;
61     for (int a=0;a<l;a++)
62     {
63         if (p->next[s[a]-'a']==NULL)
64         {
65             printf("0\n");
66             return;
67         }
68         p=p->next[s[a]-'a'];
69     }
70     printf("%d ",(int)p->id.size());
71     int upper=min(k,(int)p->id.size());
72     for (int a=0;a<upper;a++)
73         printf("%d ",p->id[a]-1);
74     printf("\n");
75 }
76 
77 int main()
78 {
79 
80     scanf("%d%d",&n,&m);
81     root=newnode();
82     for (int a=1;a<=n;a++)
83     {
84         scanf("%d",&z[a]);
85         int num;
86         scanf("%d",&num);
87         for (int b=1;b<=num;b++)
88             insert(a);
89     }
90     dfs(root);
91     for (int a=1;a<=m;a++)
92         query();
93 
94     return 0;
95 }

 

第二题:

 

水DP,先算出到每个点不删边的答案,然后枚举删掉哪条边,然后算出答案即可。

 

View Code
 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 
 7 using namespace std;
 8 
 9 const int maxn=10010;
10 const int maxm=100010;
11 
12 int n,m,en,l,z[maxn],sum[maxn],in[maxn];
13 
14 long double f[maxn],p[maxn];
15 
16 struct edge
17 {
18     int e,d;
19     edge *next;
20 }*v[maxn],ed[maxm];
21 
22 void add_edge(int s,int e,int d)
23 {
24     en++;
25     ed[en].next=v[s];v[s]=ed+en;v[s]->e=e;v[s]->d=d;
26 }
27 
28 int main()
29 {
30     scanf("%d%d",&n,&m);
31     for (int a=1;a<=m;a++)
32     {
33         int s,e,d;
34         scanf("%d%d%d",&s,&e,&d);
35         s++;e++;
36         add_edge(s,e,d);
37         sum[s]+=d;
38         in[e]++;
39     }
40     for (int a=1;a<=n;a++)
41         if (!in[a])
42         {
43             l++;
44             z[l]=a;
45         }
46     for (int a=1;a<=n;a++)
47         for (edge *e=v[z[a]];e;e=e->next)
48         {
49             in[e->e]--;
50             if (!in[e->e])
51             {
52                 l++;
53                 z[l]=e->e;
54             }
55         }
56     p[1]=1;
57     for (int a=1;a<=n;a++)
58         for (edge *e=v[z[a]];e;e=e->next)
59             p[e->e]+=p[z[a]]*e->d/sum[z[a]];
60     for (int a=n;a>=1;a--)
61         for (edge *e=v[z[a]];e;e=e->next)
62             f[z[a]]+=(f[e->e]+1)*e->d/sum[z[a]];
63     long double ans=f[1];
64     for (int a=1;a<=n;a++)
65         for (edge *e=v[z[a]];e;e=e->next)
66             if (e->d!=sum[z[a]]) ans=max(ans,f[1]+p[z[a]]*((f[z[a]]-(f[e->e]+1)*e->d/sum[z[a]])*sum[z[a]]/(sum[z[a]]-e->d)-f[z[a]]));
67     printf("%.6lf\n",(double)ans);
68 
69     return 0;
70 }

 

第三题:

 

这题怎么乱搞都行啊………………不过数据好像有问题…………囧…………

 

(暂无)

 

Day 10:

 

第一题:

 

考虑从每个点开始会有四个方向,我们只考虑其中某一个方向,比如说朝右下,这个时候我们可以发现这条直线上的x+y值是不变的,那么我们只需要按照x+y为第一关键字排个序,就能知道每个点朝右下走下一次会到哪一个点上去,那么对每个方向都做一个这样的处理。然后每次我们从每个点暴力向外走,由于每个点最多只会被经过两次,那么暴力走的这一块的复杂度是O(n)的。

 

(暂无)

 

第二题:

 

考虑最上面、最下面、最左面、左右面右4个顶点,而我们只有三个正方形,那么一定会有一个正方形覆盖到整个大矩形的一个角。有了这个性质之后就很好做了,我们首先二分答案,然后枚举第一个矩形放在了哪个角,然后剩下两个矩形一样的做法就可以了。

 

View Code
 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<algorithm>
 5 
 6 using namespace std;
 7 
 8 const int maxn=100010;
 9 const int INF=0x3f3f3f3f;
10 
11 int n,minx=INF,miny=INF,maxx=-INF,maxy=-INF,x[maxn],y[maxn],in[maxn];
12 
13 bool inside(int x1,int y1,int r,int x2,int y2)
14 {
15     return (x2>=x1) && (x2<=x1+r) && (y2>=y1) && (y2<=y1+r);
16 }
17 
18 bool check_tap2(int xx,int yy,int r)
19 {
20     for (int a=1;a<=n;a++)
21         if (inside(xx,yy,r,x[a],y[a])) in[a]++;
22     int x1=INF,x2=-INF,y1=INF,y2=-INF;
23     for (int a=1;a<=n;a++)
24         if (!in[a])
25         {
26             x1=min(x1,x[a]);
27             y1=min(y1,y[a]);
28             x2=max(x2,x[a]);
29             y2=max(y2,y[a]);
30         }
31     for (int a=1;a<=n;a++)
32         if (inside(xx,yy,r,x[a],y[a])) in[a]--;
33     if (x2-x1<=r && y2-y1<=r) return true;
34     return false;
35 }
36 
37 bool check_tap(int xx,int yy,int r)
38 {
39     for (int a=1;a<=n;a++)
40         if (inside(xx,yy,r,x[a],y[a])) in[a]++;
41     int x1=INF,x2=-INF,y1=INF,y2=-INF;
42     for (int a=1;a<=n;a++)
43         if (!in[a])
44         {
45             x1=min(x1,x[a]);
46             y1=min(y1,y[a]);
47             x2=max(x2,x[a]);
48             y2=max(y2,y[a]);
49         }
50     if (x1==INF)
51     {
52         for (int a=1;a<=n;a++)
53             if (inside(xx,yy,r,x[a],y[a])) in[a]--;
54         return true;
55     }
56     bool able=check_tap2(x1,y1,r) || check_tap2(x1,y2-r,r) || check_tap2(x2-r,y1,r) || check_tap2(x2-r,y2-r,r);
57     for (int a=1;a<=n;a++)
58         if (inside(xx,yy,r,x[a],y[a])) in[a]--;
59     return able;
60 }
61 
62 bool check(int r)
63 {
64     if (check_tap(minx,miny,r) || check_tap(minx,maxy-r,r) || check_tap(maxx-r,miny,r) || check_tap(maxx-r,maxy-r,r)) return true;
65     else return false;
66 }
67 
68 int main()
69 {
70     scanf("%d",&n);
71     for (int a=1;a<=n;a++)
72     {
73         scanf("%d%d",&x[a],&y[a]);
74         minx=min(minx,x[a]);
75         miny=min(miny,y[a]);
76         maxx=max(maxx,x[a]);
77         maxy=max(maxy,y[a]);
78     }
79     int l=0,r=1000000000;
80     while (l+1!=r)
81     {
82         int m=(l+r)>>1;
83         if (check(m)) r=m;
84         else l=m;
85     }
86     printf("%d\n",r);
87 
88     return 0;
89 }

 

第三题:

 

考虑会出现冲突的情况只有s1<s2 and t1>s2 and t1<t2这一种情况,那么我们…………………………………………………………………………………………………………

 

(暂无) 

 

(关于有部分还没有的东西,以后会慢慢更新的…………)

 

posted @ 2012-12-20 22:23  zhonghaoxi  阅读(802)  评论(2编辑  收藏  举报
BYRBT