【ContestHunter】【弱省胡策】【Round6】

KMP/DP+树链剖分+线段树/暴力


  今天考的真是……大起大落……

String

  QwQ题意理解又出错了……(还是说一开始理解了,后来自己又忘了为什么是这样了?)

  反正最后的结果就是……我当成:后面每行只需要和第一行check一下就可以了。

  因为那个图真的很像在搞串的匹配啊……一格一格往过移,看能不能匹配

  然后不就是每个s[i]对A取一下模,然后KMP?看有多少个位置能匹配咯。。。

  (其实这是A=B时的做法)

  将原序列增长一倍(复制一遍),对A取模做一遍,然后再对B取模做一遍,看有哪些位置是合法的,统计一下……

  然而其实正解可以证明出来当$A \not = B$的时候,可以当A=B做……也就是说,上面那种做法……是可以AC的-_-b

 

  P.S.正解是KMP来找循环节= = n如果可以整除n-next[n],那么循环节长度就是n-next[n]……可匹配长度就是……那么多……啊反正差不多啦

 1 //Round6 A
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<iostream>
 6 #include<algorithm>
 7 #define rep(i,n) for(int i=0;i<n;++i)
 8 #define F(i,j,n) for(int i=j;i<=n;++i)
 9 #define D(i,j,n) for(int i=j;i>=n;--i)
10 #define pb push_back
11 using namespace std;
12 typedef long long LL;
13 inline int getint(){
14     int r=1,v=0; char ch=getchar();
15     for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1;
16     for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch;
17     return r*v;
18 }
19 const int N=2000010;
20 /*******************template********************/
21 
22 
23 int a[N],b[N],c[N],A,B,n,ans,nxt[N];
24 bool yes[N];
25 void init(){
26     n=getint(); A=getint(); B=getint();
27     F(i,1,n) a[i]=getint();
28     memset(yes,0,sizeof yes);
29     ans=0;
30 }
31 void KMP(int *s,int n){
32     int m=n*2;
33     nxt[1]=0; int j=0;
34     F(i,2,n+1){
35         while(j && s[i]!=s[j+1]) j=nxt[j];
36         if (s[i]==s[j+1]) j++;
37         nxt[i]=j;
38     }
39     j=0;
40     F(i,2,m-1){
41         while(j && b[i]!=s[j+1]) j=nxt[j];
42         if (b[i]==s[j+1]) j++;
43         if (j==n) yes[i]=1,j=nxt[j];
44     }
45 }
46 void work(){
47     F(i,1,n) c[i]=b[i]=b[i+n]=a[i]%A;
48     KMP(c,n);
49     if (A!=B){
50         F(i,1,n) c[i]=b[i]=b[i+n]=a[i]%B;
51         KMP(c,n);
52     }
53     F(i,n,n*2-1) ans+=yes[i];
54     printf("%d\n",ans?ans+1:0);
55 }
56 int main(){
57     int T=getint();
58     while(T--){
59         init();
60         work();
61     }
62     return 0;
63 }
View Code

Tree

  ……30分的做法其实就是直接TreeDP,40~50的做法是线段树维护最大连续子段和,那么满分做法?两者结合……Orzzzzzz

  所以就是树链剖分+DP(并没有?其实是贪心?)啊……

  Orz zyf,这题代码感觉细节很多啊……

  树链剖分一下,权值沿轻链按TreeDP的思路将权值加到fa上面,建出整个线段树……

  然后每次修改的时候,先将这个点x到top[x]这一条重链上的ans更新一下(这里重点是maxl,即从左端点开始的最大连续子段和),然后!更新fa[top[x]]的DP值!因为它在线段树上的权值是自身权值+轻链的maxl,怎么搞?区间查询一下top[x]所在的重链的maxl……然后更新。。。【这里我并不知道如何记重链的结尾……因为dfs序记start和end是子树的,所以并不能那样搞。。。zyf的做法是:往出连轻链的时候多++一下dfs_clock,这样就可以将不同的重链断开,(当然是将这些没有编号的空节点的权值置为-INF)

  查询的时候……直接出解呗。。。

  1 //Round6 B
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cstdlib>
  5 #include<iostream>
  6 #include<algorithm>
  7 #define rep(i,n) for(int i=0;i<n;++i)
  8 #define F(i,j,n) for(int i=j;i<=n;++i)
  9 #define D(i,j,n) for(int i=j;i>=n;--i)
 10 #define pb push_back
 11 using namespace std;
 12 typedef long long LL;
 13 inline int getint(){
 14     int r=1,v=0; char ch=getchar();
 15     for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1;
 16     for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch;
 17     return r*v;
 18 }
 19 const int N=500010,INF=1000000000;
 20 /*******************template********************/
 21 
 22 int head[N],to[N],nxt[N],cnt;
 23 void add(int x,int y){
 24     to[++cnt]=y; nxt[cnt]=head[x]; head[x]=cnt;
 25     to[++cnt]=x; nxt[cnt]=head[y]; head[y]=cnt;
 26 }
 27 
 28 int n,m,f[N],id[N],v[N],ans;
 29 int pos[N],dfs_clock,fa[N],son[N],size[N],top[N];
 30 struct node{
 31    int max,maxl,maxr;
 32    LL sum;
 33 }t[N];
 34 bool vis[N];
 35 
 36 void dfs(int x){
 37     size[x]=1; son[x]=0;
 38     int mx=0;
 39     for(int i=head[x];i;i=nxt[i])
 40         if (to[i]!=fa[x]){
 41             fa[to[i]]=x;
 42             dfs(to[i]);
 43             size[x]+=size[to[i]];
 44             if (size[to[i]]>mx) son[x]=to[i],mx=size[to[i]];
 45         }
 46 }
 47 void connect(int x,int f){
 48     pos[x]=++m; top[x]=f; vis[x]=1;
 49     id[m]=x;
 50     if (son[x]) connect(son[x],f);
 51     for(int i=head[x];i;i=nxt[i])
 52         if (!vis[to[i]])
 53             ++m,connect(to[i],to[i]);
 54 }
 55 
 56 #define L (o<<1)
 57 #define R (o<<1|1)
 58 #define mid (l+r>>1)
 59 node maintain(node a,node b){
 60     node ans;
 61     ans.maxl=max((LL)a.maxl,a.sum+b.maxl);
 62     ans.maxr=max((LL)b.maxr,b.sum+a.maxr);
 63     ans.max=max(a.maxr+b.maxl,max(a.max,b.max));
 64     ans.sum=a.sum+b.sum;
 65     return ans;
 66 }
 67 void update(int o,int l,int r,int p,int v){
 68     if (l==r){
 69         t[o].sum+=v;
 70         t[o].maxl=t[o].maxr=t[o].max=max(t[o].sum,(LL)0);
 71     }else{
 72         if (p<=mid) update(L,l,mid,p,v);
 73         else update(R,mid+1,r,p,v);
 74         t[o]=maintain(t[L],t[R]);
 75     }
 76 }
 77 node query(int o,int l,int r,int ql,int qr){
 78     if (l==ql && r==qr) return t[o];
 79     else if (qr<=mid) return query(L,l,mid,ql,qr);
 80     else if (ql>mid) return query(R,mid+1,r,ql,qr);
 81     else return maintain(query(L,l,mid,ql,mid),query(R,mid+1,r,mid+1,qr));
 82 }
 83 void change(int x,int y1,int y2){
 84     while(x){
 85         int y=top[x],z=query(1,1,m,pos[y],m).maxl;
 86         update(1,1,m,pos[x],y2-y1);
 87         y1=z; y2=query(1,1,m,pos[y],m).maxl;
 88         x=fa[top[x]];
 89     }
 90 }
 91 
 92 int main(){
 93 #ifndef ONLINE_JUDGE
 94     freopen("sub.in","r",stdin);
 95     freopen("sub.out","w",stdout);
 96 #endif
 97     n=getint(); int T=getint();
 98     F(i,1,n) v[i]=getint();
 99     F(i,2,n){
100         int x=getint(),y=getint();
101         add(x,y);
102     }
103     dfs(1); connect(1,1);
104     F(i,1,m) if (!id[i]) update(1,1,m,i,-INF);
105     F(i,1,n) change(i,0,v[i]);
106     while(T--){
107         int cmd=getint(),x,y;
108         if (cmd==1){
109             x=getint(), y=getint();
110             change(x,v[x],y);
111             v[x]=y;
112         }else printf("%d\n",t[1].max);
113     }
114     return 0;
115 }
View Code

Transport

  ……我就无语了……

  一开始我想的是二分!然后模拟过程进行判断!然而连样例都过不了……QwQ

  仔细想了想好像确实并不满足单调性……会有小的波动……

  然后蒟蒻就不会了……实在没办法了,二分的时候边界不是 $L=max\{a[i]\},R=\sum a[i]$ 嘛= =然后我就直接将二分的过程删掉……改成枚举……然后……TM居然就过了……maya我也是惊呆了,这个枚举的上下界明明很大的好吗……如果全都走一遍肯定要T的啊!然而我就是过了……就是这么神奇……>_>

  P.S.这个边界 L 还是比较松的,其实应该弄成$max\{ \frac{\sum a[i]}{k}, max(a[i]) \}$ ?

 1 //Round6 C
 2 #include<cstdio>
 3 #include<set>
 4 #include<cstring>
 5 #include<cstdlib>
 6 #include<iostream>
 7 #include<algorithm>
 8 #define rep(i,n) for(int i=0;i<n;++i)
 9 #define F(i,j,n) for(int i=j;i<=n;++i)
10 #define D(i,j,n) for(int i=j;i>=n;--i)
11 #define pb push_back
12 using namespace std;
13 typedef long long LL;
14 inline int getint(){
15     int r=1,v=0; char ch=getchar();
16     for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1;
17     for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch;
18     return r*v;
19 }
20 const int N=100010;
21 /*******************template********************/
22 
23 int n,k,a[N],sum;
24 multiset<int>s,s2;
25 multiset<int>::iterator it;
26 bool check(int c){
27     if (k*c<sum) return 0;
28     s2=s;
29     int num;
30     F(i,1,k){
31         num=c;
32         do{
33             if (s2.empty()) return 1;
34             it=s2.lower_bound(num);
35             if (it==s2.end()) it--;
36             if (*it>num){
37                 if (it==s2.begin()) break;
38                 else it--;
39             }
40             num-=*it;
41             s2.erase(it);
42         }while(1);
43     }
44     return s2.empty();
45 }
46 void init(){
47     n=getint(); k=getint();
48     s.clear();
49     int L=0,R=0;
50     sum=0;
51     F(i,1,n){
52         a[i]=getint();
53         sum+=a[i]; R+=a[i]; L=max(L,a[i]);
54         s.insert(a[i]);
55     }
56     F(i,L,R)
57         if (check(i)){
58             printf("%d\n",i);
59             return;
60         }
61 }
62 
63 int main(){
64 #ifndef ONLINE_JUDGE
65     freopen("C.in","r",stdin);
66     freopen("C.out","w",stdout);
67 #endif
68     int T=getint();
69     while(T--) init();
70     return 0;
71 }
View Code

 

posted @ 2015-06-16 20:18  Tunix  阅读(326)  评论(0编辑  收藏  举报