码迷,mamicode.com
首页 > 其他好文 > 详细

ZQSZ && LWYZ 胡策记录

时间:2017-11-07 00:11:41      阅读:224      评论:0      收藏:0      [点我收藏+]

标签:定时   最长前缀   noip   targe   费用流   math   none   文章   cli   

此文为博主原创,转载...转载这种文章有意思吗qwq

严禁各OJ在未经博主同意的情况下擅自使用博文中的题面作为OJ题目。

今天做的是我校dalao@wzy出的套题w【被长达6页的题面淹没】

dalao的题就是难...T1就懵逼了...3.5h不知道自己都干了些什么...

最后80+30+0+0  rank7滚粗。

感觉这次题好多人都翻车了,我这么菜到底是怎么rank7 的QAQ

NOIP2017 RP ++

 

A.谜团

题目大意:

谜团在第一秒会转化一个“虚灵”,之后的时间内将不再转化单位。新

产生的“虚灵”会在下一秒分裂出m 个“虚灵”,原有的“虚灵”仍然存在,并且不再产生虚灵。

新产生的“虚灵”可在下一秒分裂,之后也不再产生“虚灵”。

给定时间 t 和分裂数m,问在 t 秒后,谜团拥有多少个“虚灵”。答案可能很大,要求你模一个数k(不保证k是质数)。

数据范围:

1<=k<=10^8,1<=m<=100,1<=t<=2^31-1

 

分析:

这题的部分分范围我没有贴...(你什么时候贴过部分分范围啊喂!)

经过推导可以发现,题目的答案其实就是对首项为1,公比为m的等比数列求和。答案为S(t-1)。

直接暴力做的话可以拿40分。

部分分中有一部分是保证m与k互质的,此时可以用等比数列求和公式+逆元,加上暴力部分的数据分治,80分。

满分做法:S(n+m)=S(n)+S(m)*qn

sum(p,c)表示计算 p^0 + p^1 + ... + p^c

如果c是偶数,答案就是 p^0 + p^1 + ... + p^(c/2 - 1) * (1 + 2^(c/2)) + p^c

展开得到 p^0 + p^1 + ... + p^(c/2 - 1) + p^(c/2) + p^(c/2+1) + ... + p^c

如果c是奇数  那么答案就是  p^0 + p^1 + ... + p^(c/2) * (1 + 2^(c/2 + 1))

展开得到 p^0 + p^1 + ... + p^(c/2) + p^(c/2 + 1) + ... + p^c

用一个递归函数计算即可。

AC代码:

 

技术分享
 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cmath>
 4 #include<cstring>
 5 
 6 inline void read(long long &x)
 7 {
 8     char ch = getchar(),c = ch;x = 0;
 9     while(ch < 0 || ch > 9) c = ch,ch = getchar();
10     while(ch <= 9 && ch >= 0) x = (x<<1)+(x<<3)+ch-0,ch = getchar();
11     if(c == -) x = -x;
12 }
13 
14 long long k,m,t,ans;
15 //S(n+m) = S(n)+S(m)*q^n
16 long long ksm(int b)
17 {
18     long long base = m,r = 1;
19     for(;b;b>>=1)
20     {
21         if(b&1) r = r*base%k;
22         base = base*base%k;
23     }
24     return r;
25 }
26 
27 long long calc(int t)
28 {
29     if(t == 0) return 1;
30     if(t&1) return (calc(t/2)*(1+ksm(t/2+1))%k)%k;
31     else return (calc(t/2-1)*(1+ksm(t/2))%k+ksm(t))%k;
32 }
33 
34 int main()
35 {
36     read(m),read(t),read(k);
37     printf("%lld\n",calc(t-1)%k);
38     return 0;
39 }
mituan

 

 

B.祈求者

题目大意:

有一个长度为k的字符串和n个字符集合。你可以从每个字符集合中选择至多1个字符,使它们拼成

字符串的前缀。求能够拼出的最长前缀。

输入的第一个字母为T,表示接下来有T组数据。

数据范围:

1<=T<=20,1<= Σai+n <= 200,1 <= k <= 200.

 

分析:

如果把题目改成这样:

【从每个字符集合中选择至多一个字符,尽量多地、连续地匹配前缀】

是不是很容易就想到了二分图匹配呀。

最大流也可做,不过当时这题有dalao用费用流拿了100分,向dalao低头www

如果1~mid能够匹配,则1~mid-1也一定能匹配;1~mid不能完全匹配,1~mid+1也不能完全匹配,可以二分。

二分能够匹配的前缀的最长长度,对于每次二分出的长度,做一次二分图匹配。

如果匹配数==二分的长度,说明该长度是可行的。

AC代码:

技术分享
 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cmath>
 4 #include<cstring>
 5 
 6 inline void read(int &x)
 7 {
 8     char ch = getchar(),c = ch;x = 0;
 9     while(ch < 0 || ch > 9) c = ch,ch = getchar();
10     while(ch <= 9 && ch >= 0) x = (x<<1)+(x<<3)+ch-0,ch = getchar();
11     if(c == -) x = -x;
12 }
13 
14 int t,n,l,r,mid,ans,cnt,len,tmp;
15 int head[6000],link[500],vis[500];
16 char s[202],glo[202][202];
17 
18 struct Edge
19 {
20     int f,t,nxt;
21 }e[6000];
22 
23 void insert(int f,int t)
24 {
25     e[++cnt].f = f,e[cnt].t = t;
26     e[cnt].nxt = head[f];
27     head[f] = cnt;
28 }
29 
30 bool dfs(int now)
31 {
32     for(int i = head[now];i;i = e[i].nxt)
33     {
34         int to = e[i].t;
35         if(vis[to]) continue;
36         vis[to] = 1;
37         if(!link[to] || dfs(link[to]))
38         {
39             link[to] = now;
40             return true;
41         }
42     }
43     return false;
44 }
45 
46 bool check(int x)
47 {
48     memset(link,0,sizeof(link));
49     memset(head,0,sizeof(head));
50     memset(e,0,sizeof(e));cnt = 0;
51     int res = 0;
52     for(int l = 1;l <= x;++ l)
53         for(int i = 1;i <= n;++ i)
54         {
55             tmp = strlen(glo[i]+1);
56             for(int j = 1;j <= tmp;++ j)
57                 if(glo[i][j] == s[l])
58                     insert(l,i);
59         }    
60     for(int i = 1;i <= x;++ i)
61     {
62         memset(vis,0,sizeof(vis));
63         if(dfs(i)) res ++;
64     }
65 //    printf("%d %d\n",cnt,r);
66     if(res == x) return true;
67     else return false;
68 }
69 
70 int main()
71 {
72 //    freopen("kaer.in","r",stdin);
73 //    freopen("kaer.out","w",stdout);
74     freopen("1.txt","r",stdin);
75     read(t);
76     while(t -- )
77     {
78         read(n);
79         for(int i = 1;i <= n;++ i)
80             scanf("%s",&glo[i][1]);
81         scanf("%s",s+1);
82         len = strlen(s+1);
83         l = 1,r = len,ans = 0;
84         while(l <= r)
85         {
86             mid = (l+r)>>1;
87             if(check(mid)) l = mid+1,ans = mid;
88             else r = mid-1;
89         }
90         printf("%d\n",ans);
91     }
92     return 0;
93 }
kaer

 

C.大地之灵

题目大意:

有三种颜色点,不同颜色的点之间可以任意连边,同色的点之间必须间隔至少2个其他颜色的点才能连边。

给出这三种点的个数n,m,k,求连边的方案数。答案%1e9+7。

数据范围:

1 <= n,m,k <= 5000

 

分析:

先考虑有两种点的情况。由题意可知,此时每个点的出度最多为1,边数最多为Min(a,b)。

把边分别编号为1,2,3...n,进行DP。

dp[i]表示连了i条边的方案数。转移方程:dp[i] = dp[i-1]*(a-i+1)*(b-i+1)/i

转移比较容易想到,但是为什么要除以i可能不容易理解。

因为连的边是无序的,但是为了方便DP,你给边钦定了顺序。

这样一来就会导致:完全相同的两条边,编号为1,2时计算一次,编号为2,1时计算一次。

最终答案为Σdp[i]

同理,当有三种颜色时,只需要把这个过程做三次,乘起来即可。

AC代码:

技术分享
 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cmath>
 4 #include<cstring>
 5 
 6 const int MOD = 1e9+7;
 7 inline void read(int &x)
 8 {
 9     char ch = getchar(),c = ch;x = 0;
10     while(ch < 0 || ch > 9) c = ch,ch = getchar();
11     while(ch <= 9 && ch >= 0) x = (x<<1)+(x<<3)+ch-0,ch = getchar();
12     if(c == -) x = -x;
13 }
14 
15 int n,m,k;
16 long long ans,dp[25000001];
17 
18 inline int Max(int a,int b)
19 {return a>b?a:b;}
20 
21 long long calc(int a,int b)
22 {
23     long long r = 0;
24     for(int i = 1;i <= 25000000;++ i)
25         if(!dp[i]) break;
26         else dp[i] = 0;
27     dp[0] = 1;
28     int mx = Max(a,b);
29     for(int i = 1;i <= mx;++ i)
30         dp[i] = (dp[i-1]*(a-i+1)*(b-i+1)/i)%MOD;
31     for(int i = 0;i <= mx;++ i)
32         r = (r+dp[i])%MOD;
33     return r;
34 }
35 
36 int main()
37 {
38     read(n),read(m),read(k);
39     ans = calc(n,m)*calc(n,k)%MOD *calc(m,k)%MOD;
40     printf("%lld\n",ans);
41     return 0;
42 }
ES

 

 

D.裂魂人

题目大意:

给你一张n 个点,m 条边的无向图(没有重边,没有自环),每条边有一个边权w。

输出起点为S,终点为E,且恰好经过k 条边的最短路长度。

不保证起点和终点不是同一个点,保证有解。点的编号为1,2,...,n

数据范围:

3 <= n <= 200, 2 <= m <= 200,1 <= w <= 1000,k<= 1,000,000

分析:

这什么蛇皮题目!我不做辣!

正解:Floyd倍增+矩阵快速幂加速DP

反正我是不会的qwq读者有意向的话可以问@wzydalao

 

ZQSZ && LWYZ 胡策记录

标签:定时   最长前缀   noip   targe   费用流   math   none   文章   cli   

原文地址:http://www.cnblogs.com/shingen/p/7795801.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!