20180329小测

让大家都AK的信心赛......
话说这种考试有什么意思(不),还不如做我出的那套模拟题呢......

T1:


其实这题是我三道题里AC得最晚的......
首先我们能用bitset+大力背包骗到58-64分......
考虑我们如果先枚举两个数能组合出的值,再计算另外一个数的方案数,什么情况下会算重?
显然是当这个值取模最后的那个数相同的时候,这样一个方案数会被计算多次!
此外还有一个十分显然的结论:当两个值取模最后那个数相同时,较大的那个值的答案会被包含在较小的那个值的答里面。
这样的话,我们在取模abc中某一个数的同余系下跑一个最短路,用另外两个数做边进行转移,最后再统计一发答案不就好了。
60分bitset代码:

 1 #pragma GCC optimize(3)
 2 #include<cstdio>
 3 #include<bitset>
 4 const int maxn=1e8+1e2;
 5 std::bitset<maxn> vis;
 6 
 7 long long h;
 8 int a,b,c,ans;
 9 
10 
11 int main() {
12     scanf("%lld%d%d%d",&h,&a,&b,&c);
13     if( a == 1 || b == 1 || c == 1 ) return printf("%lld\n",h),0;
14     for(int i=0;a*i<h;i++) {
15         if( vis[a*i] ) break;
16         for(int j=0;a*i+b*j<h;j++) {
17             if( vis[a*i+b*j] ) break;
18             for(int k=0;a*i+b*j+k*c<h;k++) {
19                 if( vis[a*i+b*j+k*c] ) break;
20                 vis[a*i+b*j+k*c] = 1;
21             }
22         }
23     }
24     printf("%llu\n",vis.count());
25     return 0;
26 }
View Code

正解代码:

 1 #include<bits/stdc++.h>
 2 #define bool unsigned char
 3 typedef long long int lli;
 4 using namespace std;
 5 const int maxn=1e5+1e2;
 6 
 7 lli h,ans;
 8 lli dis[maxn];
 9 int s[maxn],t[maxn<<4],nxt[maxn<<4],l[maxn<<4];
10 bool inq[maxn];
11 int a,b,c;
12 
13 inline void addedge(int from,int to,int len) {
14     static int cnt = 0;
15     t[++cnt] = to , l[cnt] = len ,
16     nxt[cnt] = s[from] , s[from] = cnt;
17 }
18 inline void spfa(int st) {
19     memset(dis,0x7f,sizeof(dis)) , dis[st] = 0;
20     queue<int> q; q.push(st) , inq[st] = 1;
21     while( q.size() ) {
22         const int pos = q.front(); q.pop() , inq[pos] = 0;
23         for(int at=s[pos];at;at=nxt[at])
24             if( dis[t[at]] > dis[pos] + l[at] ) {
25                 dis[t[at]] = dis[pos] + l[at];
26                 if( !inq[t[at]] ) q.push(t[at]) , inq[t[at]] = 1;
27             }
28     }
29 }
30 inline void getans() {
31     --h;
32     for(int i=0;i<c;i++)
33         if( dis[i] <= h )
34             ans += ( h - dis[i] ) / c + 1;
35 }
36 
37 int main() {
38     scanf("%lld%d%d%d",&h,&a,&b,&c);
39     if( a > b ) swap(a,b);
40     if( b > c ) swap(b,c);
41     for(int i=0;i<c;i++)
42         addedge(i,(i+a)%c,a) , addedge(i,(i+b)%c,b);
43     spfa(0);
44     getans();
45     printf("%lld\n",ans);
46     return 0;
47 }
View Code

 

T2:


怕不是stl:rope裸题......
rope能实现区间提取,单点插入区间,正好能用来做这道题......
代码:

 1 #include<iostream>
 2 #include<ext/rope>
 3 const int maxn=2.5e5+1e2;
 4 
 5 char in[maxn];
 6 __gnu_cxx::rope<char> str,ans;
 7 
 8 int main() {
 9     static char com[10];
10     static int k,len;
11     std::ios::sync_with_stdio(0) , std::cin.tie(0) , std::cout.tie(0);
12     std::cin >> in , str = in;
13     while( ( std::cin >> com ) && *com != 'E' ) {
14         if( *com == 'I' ) {
15             std::cin >> in >> k;
16             str.insert(k,in);
17         } else if( *com == 'P' ) {
18             std::cin >> k >> len;
19             ans = str.substr(k,len-k+1);
20             std::cout << ans << std::endl;
21         }
22     }
23     return 0;
24 }
View Code

 

T3:


如果只是求和应该怎样做?一个很显然的换根树状DP。
现在要求k次呢?这样的话距离+1-1就需要进行变化了。
我们维护x^0~x^k的一个多项式,在更新x^k的时候利用二项式定理和更低次的项进行更新就好了。
这样一次更新复杂度O(k),总复杂度O(nkt),稳稳地AC了。
根节点深度为1好评,省去了对于0^k等问题的繁琐的分类讨论......
代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #define debug cout
  6 typedef long long int lli;
  7 using namespace std;
  8 const int maxn=2e4+1e2,maxk=25;
  9 const int mod=1e9+7;
 10 
 11 
 12 lli c[maxk][maxk];
 13 int n,k;
 14 
 15 namespace Pre {
 16     lli fac[maxk],inv[maxk];
 17     inline lli fastpow(lli base,int tim) {
 18         lli ret = 1;
 19         while( tim ) {
 20             if( tim & 1 ) ret = ret * base % mod;
 21             if( tim >>= 1 ) base = base * base % mod;
 22         }
 23         return ret;
 24     }
 25     inline lli C(int n,int m) {
 26         return fac[n] * inv[m] % mod * inv[n-m] % mod;
 27     }
 28     inline void work() {
 29         *fac = 1;
 30         for(int i=1;i<=k;i++) fac[i] = fac[i-1] * i % mod;
 31         inv[k] = fastpow(fac[k],mod-2);
 32         for(int i=k;i;i--) inv[i-1] = inv[i] * i % mod;
 33         for(int i=0;i<=k;i++)
 34             for(int j=0;j<=i;j++)
 35                 c[i][j] = C(i,j);
 36     }
 37 }
 38 
 39 struct Poly {
 40     lli dat[maxk];
 41     Poly() {
 42         memset(dat,0,sizeof(dat));
 43     }
 44     lli& operator [] (const int &x) {
 45         return dat[x];
 46     }
 47     const lli& operator [] (const int &x) const {
 48         return dat[x];
 49     }
 50     friend Poly operator + (const Poly &a,const Poly &b) {
 51         Poly ret;
 52         for(int i=0;i<=k;i++)
 53             ret[i] = ( a[i] + b[i] ) % mod;
 54         return ret;
 55     }
 56     friend Poly operator - (const Poly &a,const Poly &b) {
 57         Poly ret;
 58         for(int i=0;i<=k;i++)
 59             ret[i] = ( a[i] - b[i] + mod ) % mod;
 60         return ret;
 61     }
 62     friend Poly operator + (const Poly &a,lli x) {
 63         Poly ret; x = ( x + mod ) % mod;
 64         static lli pows[maxk];
 65         *pows = 1;
 66         for(int i=1;i<=k;i++) pows[i] = pows[i-1] * x % mod;
 67         for(int i=k;~i;i--) {
 68             for(int j=i;~j;j--)
 69                 ret[i] += a[j] * pows[i-j] % mod * c[i][j] % mod , ret[i] %= mod;
 70         }
 71         return ret;
 72     }
 73     inline void init() {
 74         for(int i=0;i<=k;i++) dat[i] = 1;
 75     }
 76 }sson[maxn],sfa[maxn],f[maxn];
 77 // sson is dis of points in subtree to pos .
 78 
 79 int s[maxn],t[maxn<<1],nxt[maxn<<1],fa[maxn],cnt;
 80 
 81 inline void addedge(int from,int to) {
 82     t[++cnt] = to , nxt[cnt] = s[from] , s[from] = cnt;
 83 }
 84 inline void dfsson(int pos) {
 85     sson[pos].init();
 86     for(int at=s[pos];at;at=nxt[at]) if( t[at] != fa[pos] ) {
 87         fa[t[at]] = pos , dfsson(t[at]);
 88         sson[pos] = sson[pos] + ( sson[t[at]] + 1 ) ;
 89     }
 90 }
 91 inline void dfsfa(int pos) {
 92     if( fa[pos] ) {
 93         sfa[pos] = sfa[fa[pos]] + 1;
 94         Poly delta = sson[fa[pos]] - ( sson[pos] + 1 );
 95         sfa[pos] = sfa[pos] + ( delta + 1 );
 96     }
 97     for(int at=s[pos];at;at=nxt[at]) if( t[at] != fa[pos] ) dfsfa(t[at]);
 98 }
 99 inline void getans() {
100     for(int i=1;i<=n;i++) {
101         Poly sum = sfa[i] + sson[i];
102         printf("%lld\n",sum.dat[k]);
103     }
104     putchar('\n');
105 }
106 
107 int main() {
108     while( scanf("%d%d",&n,&k) == 2 ) {
109         memset(s,0,sizeof(int)*(n+1)) , cnt = 0;
110         Pre::work();
111         for(int i=1,a,b;i<n;i++) {
112             scanf("%d%d",&a,&b) ,
113             addedge(a,b) , addedge(b,a);
114         }
115         dfsson(1) , dfsfa(1);
116         getans();
117     }
118     return 0;
119 }
View Code

 

最后上排名。
(为什么3个AK的?因为有一个是我用我老婆的名字注册的账号(四蒸心.jpg))


话说比赛还没结束呢就发题解真的好吗?
另外我的桌子竟然带电!准备报警了!

 

posted @ 2018-03-29 11:16  Cmd2001  阅读(150)  评论(0编辑  收藏  举报