7.25题解

两道水题,都贼惨,难受。。。。。。。一大把伤心往事以及蒟蒻的自己,今天上午的我,绝对像个zz

T1

emm,KMP,hash任您挑选,当然我忘了KMP怎么玩,就去打了hash,就这想式子还想了半天,不过点和长度之间的转换最后还是被我玩死了,没倒腾对,不过我最后还是hash过的,hash的话就O(n)长度扫一遍就行了,完全可以作为hash模板题,还是我废物啊,别的就没啥可说的了,注意一下小的细节就可以了

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<string>
 5 using namespace std;
 6 #define maxn 200010
 7 #define ll long long
 8 #define ull unsigned long long
 9 int t;
10 const ll p=131;
11 char s[maxn],c[2];
12 int la,lb;
13 ull zhia[maxn],zhib[maxn],jc[maxn];
14 int check(int cd)
15 {
16     if(!cd) return 1;
17     if(zhia[cd]==(zhib[lb]-zhib[lb-cd]*jc[cd])) return 1;
18     return 0;
19 }
20 int ef(int head,int tail)
21 {
22     if(head==tail) return head;
23     if(head+1==tail) return check(tail)?tail:head;
24     int mid=(head+tail)/2;
25     if(check(mid))return ef(mid,tail);
26     else return ef(head,mid-1);
27 }
28 int main()
29 {
30     scanf("%d",&t);
31     jc[0]=1; jc[1]=p;
32     for(int i=2;i<maxn;++i) jc[i]=jc[i-1]*p;
33     while(t--)
34     {
35         memset(zhia,0,sizeof(zhia));
36         memset(zhib,0,sizeof(zhib));
37         scanf("%d%d",&la,&lb);
38         scanf("%s",s);
39         int ls;
40         for(int i=1;i<=la;++i)
41         {
42             ls=s[i-1]-'a'+1;
43             zhia[i]=zhia[i-1]*p+ls;
44             if(i<=lb) zhib[i]=zhib[i-1]*p+ls;
45         }
46         scanf("%s",c); 
47         lb++;
48         ls=c[0]-'a'+1;
49         zhib[lb]=zhib[lb-1]*p+ls;
50         int ans=0;
51         for(int i=1;i<=min(la,lb);++i)
52             if(zhia[i]==(zhib[lb]-zhib[lb-i]*jc[i])) ans=i;
53         cout<<ans<<endl;
54     }
55     return 0;
56 }
暴力出奇迹

 

T2

好好读题,多画样例,仔细思考,别跟我似的,想着啥是啥,打完就扔,我是废物,太废物了,这道题,乍一看给你一种打板子求割点就是正解的错觉,事实上坑还是在的,就是从1到n的必经点肯定是割点,但不见得割点就是必经点,因为有可能从1到n某些割点根本就不需要经过,所以这题你给他点双缩点,然后dfs从1跑到n,标记一下途中经过的割点,那些割点就是最终答案了,记得数组稍微开大一点,记请缩点前后的对应关系就没问题了

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<vector>
  4 #include<stack>
  5 #include<cstring>
  6 #define maxn 200100
  7 #define maxm 400100
  8 using namespace std;
  9 int T,n,m,js,root,tot,cnt,num,j,ans;
 10 int head[maxn],to[maxm*2],xia[maxm*2];
 11 int dfn[maxn],low[maxn],cut[maxn];
 12 int bh[maxn],ss[maxn];
 13 int h[maxn*2],t[maxm*2],x[maxm*2];
 14 int pd[maxn*2],ys[maxn*2];
 15 vector <int> ds[maxn*2];
 16 stack <int> s;
 17 void clear()
 18 {
 19     js=0;  root=0;  tot=0;  num=0;  j=0;  ans=0;
 20     while(s.empty()==false)  s.pop();
 21     for(int i=1;i<=cnt;++i)  ds[i].clear();
 22     memset(head,0,sizeof(head));  memset(to,0,sizeof(to));
 23     memset(xia,0,sizeof(xia));  memset(dfn,0,sizeof(dfn));
 24     memset(low,0,sizeof(low));  memset(cut,0,sizeof(cut));
 25     memset(bh,0,sizeof(bh));  memset(ss,0,sizeof(ss));
 26     memset(h,0,sizeof(h));  memset(t,0,sizeof(t));  memset(x,0,sizeof(x));
 27     memset(pd,0,sizeof(pd));  memset(ys,0,sizeof(ys));
 28     cnt=0;
 29 }
 30 void add(int x,int y)
 31 {
 32     to[++js]=y;  xia[js]=head[x];  head[x]=js;
 33 }
 34 void tarjan(int x)
 35 {
 36     int bj=0;  dfn[x]=low[x]=++tot;  s.push(x);
 37     if(x==root&&head[x]==0)  {ds[++cnt].push_back(x);  return ;}
 38     for(int i=head[x];i;i=xia[i])
 39     {
 40         int ls=to[i];
 41         if(dfn[ls]==0)
 42         {
 43             tarjan(ls);  low[x]=min(low[x],low[ls]);
 44             if(low[ls]>=dfn[x])
 45             {
 46                 bj++;
 47                 if(x!=root||bj>=2)  cut[x]=1;
 48                 int y;  cnt++;
 49                 do  {y=s.top();  s.pop();  ds[cnt].push_back(y);}
 50                 while(y!=ls);
 51                 ds[cnt].push_back(x);
 52             }
 53         }
 54         else  low[x]=min(low[x],dfn[ls]);
 55     }
 56 }
 57 void ADD(int a,int b)
 58 {
 59     t[++j]=b;  x[j]=h[a];  h[a]=j;
 60 }
 61 void dfs(int w)
 62 {
 63     ys[w]=1;
 64     if(pd[w]==1)  return ;
 65     for(int i=h[w];i;i=x[i])
 66     {
 67         int ls=t[i];
 68         if(ys[ls]==0)
 69         {    
 70             dfs(ls);
 71             if(pd[ls]==1)  pd[w]=1;
 72         }
 73     }
 74 }
 75 int main()
 76 {
 77     scanf("%d",&T);
 78     while(T--)
 79     {
 80         scanf("%d%d",&n,&m);
 81         for(int i=1;i<=m;++i)
 82         {
 83             int u,v;  scanf("%d%d",&u,&v);
 84             add(u,v);  add(v,u);
 85         }
 86         for(int i=1;i<=n;++i)
 87             if(dfn[i]==0)  {root=i;  tarjan(i);}
 88         num=cnt;
 89         for(int i=1;i<=n;++i)
 90             if(cut[i]==1)  bh[i]=++num;
 91         for(int i=1;i<=cnt;++i)
 92             for(int j=0;j<ds[i].size();++j)
 93             {
 94                 int ls=ds[i][j];
 95                 if(cut[ls]==1)  {ADD(i,bh[ls]);  ADD(bh[ls],i);}
 96                 else  ss[ls]=i;
 97             }
 98         if(cut[n]==1)  pd[bh[n]]=1;
 99         else  pd[ss[n]]=1;
100         if(cut[1]==1)  dfs(bh[1]);
101         else  dfs(ss[1]);
102         for(int i=2;i<n;++i)
103         {
104             int ls;
105             if(cut[i]==1)  ls=bh[i];
106             else  ls=ss[i];  
107             if(pd[ls]==1&&cut[i]==1)  ans++;
108         }
109         printf("%d\n",ans);
110         for(int i=2;i<n;++i)
111         {
112             int ls;
113             if(cut[i]==1)  ls=bh[i];
114             else  ls=ss[i];  
115             if(pd[ls]==1&&cut[i]==1)  printf("%d ",i);
116         }
117         puts("");  clear();
118     }
119     return 0;
120 }
模板出奇迹

 

T3

唯一一道不水的题,让我改了两天,什么破情况,昨天晚上真的改到自闭,回到正题

一个环,要求把颜色一样的挪到一起,这种题一般第一步都是,拆环为链变二倍,然后怎么办呢?枚举每个断点,看这么断的最少移动次数,这就O(n)起步了,再加个n什么之类的估计就死翘翘了,这题我没打部分分,就直接上正解了,(sdfz那大佬三分搞到65分,可惜我不会)

我们把$BR$的排列具化成01串,谁0谁1无所谓,我们假设把0留在中间,那么1被挪到两边需要的移动次数应该就是他移动的方向上0的个数,那么我们来想一下怎么移动最优?也就是怎么样能让每个1两边的0最少,当然是以中间的0为不动点咯,那这样的话我们记录一下每个1两边0的个数就可以了,正着倒着扫一下就好了,我们来想一下这一个序列中所有的1一共要移动的次数,$∑(qian[j]-qian[i-1])+∑(hou[j]-hou[i+len])$,来理解一下这个式子,$qian$就是刚才记录的那个前面有几个0,$hou$记录后面有几个(倒着记录),j代表为1的点,$qian[j]$中的$j$为在中间0前面的点,$hou[j]$中的$j$为在中间0后面的点,$i$代表枚举开始的点,$i+len-1$是枚举结束的点,那这个式子就是用前缀和后缀算出中间一部分,现在我们把它拆开就变成了$∑qian[j]-∑qian[i-1]+∑hou[j]-∑[i+len]$,仔细一看,这个$qian[j]$,$hou[j]$的有点前缀和的意思啊,$yes$,就是前缀和,不对,准确来说是前缀和的前缀和以及后缀和的前缀和,那式子都有了,码就完了,虽然我码了很久。。附赠一下我最后推出来的完整的式子

$ans=qh[mid]-qh[i-1]-qian[i-1]*len1+hh[mid+1]-hh[i+len]-hou[mid+1]*len2$

$len1=(mid-i+1)-(qian[mid]-qian[i-1])$

$len2=(i+len-1-(mid+1)+1)-(hou[mid]-hou[i+len])$

我打的应该不太算正解,因为我拿到的正解需要二分,我实在不觉得决策具有单调性,所以放弃了

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #define maxn 1001000
 5 #define int long long
 6 using namespace std;
 7 int t,len,tot,ans;
 8 int cun[maxn*2],qian[maxn*2],hou[maxn*2],qh[maxn*2],hh[maxn*2],jl[maxn*2];
 9 char a[maxn];
10 void clear()
11 {
12     tot=0;  ans=200000000000000000;
13     memset(cun,0,sizeof(cun));  memset(qian,0,sizeof(qian));
14     memset(hou,0,sizeof(hou));  memset(qh,0,sizeof(qh));
15     memset(hh,0,sizeof(hh));  memset(jl,0,sizeof(jl));
16 }
17 signed main()
18 {
19     scanf("%lld",&t);
20     while(t--)
21     {
22         clear();
23         scanf("%s",a+1);  len=strlen(a+1);
24         for(int i=1;i<=len;++i)
25         {
26             if(a[i]=='B')  cun[i]=1;
27             else  {cun[i]=0;  tot++;}
28         }
29         for(int i=len+1;i<=2*len;++i)  cun[i]=cun[i-len];
30         int cnt=0;  tot*=2;
31         for(int i=1;i<=2*len;++i)
32         {
33             if(cun[i]==0)  {cnt++;  jl[cnt]=i;  qian[i]=cnt;  hou[i]=tot-qian[i]+1;}
34             if(cun[i]==1)  {qian[i]=cnt;  hou[i]=tot-qian[i];}
35             if(cun[i]==0)  qh[i]=qh[i-1];
36             else  qh[i]=qh[i-1]+qian[i];
37         }
38         for(int i=2*len;i>=1;--i)
39         {
40             if(cun[i]==0)  hh[i]=hh[i+1];
41             else  hh[i]=hh[i+1]+hou[i];
42         }
43         for(int i=1;i<=len;++i)
44         {
45             int da=0;
46             int mid=(qian[i+len-1]-qian[i-1])/2+1+qian[i-1];  mid=jl[mid];
47             da=qh[mid]-qh[i-1]-qian[i-1]*(mid-i+1-qian[mid]+qian[i-1]);
48             da+=hh[mid+1]-hh[i+len]-hou[i+len]*(i+len-mid-1-hou[mid+1]+hou[i+len]);
49             ans=min(ans,da);
50         }
51         printf("%lld\n",ans);
52     }
53     return 0;
54 }
模拟?

 

posted @ 2019-07-27 21:12  hzoi_X&R  阅读(141)  评论(0编辑  收藏  举报