2021.9.14考试总结[NOIP模拟53]

T1 ZYB和售货机


容易发现把每个物品都买成$1$是没有影响的。

然后考虑最后一个物品的方案,如果从$f_i$向$i$连边,发现每个点有一个出度多个入度,可以先默认每个物品都能买且最大获利,这样可以建出每个点出度入度都是$1$的图。

把所有边都连上是一个基环树,所以建出的若干个联通图中只有一个环。而我们要做的工作就是用最小代价把这个环断掉,形成的树上所有边都可以对答案贡献。

记每个物品的最大获利和次大获利,在图上$DFS$,每到一个点先加上最大获利,记录路径上最大获利与次大获利差的最小值,如果当前这一块是环,把答案减去这个最小值即可。

$code:$

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 
 5 namespace IO{
 6     inline int read(){
 7         char ch=getchar(); int x=0,f=1;
 8         while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
 9         while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
10         return x*f;
11     }
12     inline void write(int x,char sp){
13         char ch[20]; int len=0;
14         if(x<0){ putchar('-'); x=~x+1; }
15         do{ ch[len++]=x%10+(1<<4)+(1<<5); x/=10; }while(x);
16         for(int i=len-1;~i;--i) putchar(ch[i]); putchar(sp);
17     }
18     inline int max(int x,int y){ return x<y?y:x; }
19     inline int min(int x,int y){ return x<y?x:y; }
20     inline void swap(int &x,int &y){ x^=y^=x^=y; }
21     inline void chmax(int &x,int y){ x=x<y?y:x; }
22     inline void chmin(int &x,int y){ x=x<y?x:y; }
23 } using namespace IO;
24 
25 const int NN=1e6+5;
26 int n,st,ans,cnt,mn,bel[NN],f[NN],c[NN],d[NN],a[NN],mx[NN],sc[NN],val[NN];
27 bool vis[NN];
28 
29 void dfs(int x){
30     if(bel[x]==cnt) return ans-=mn,void();
31     if(bel[x]) return;
32     if(!mx[x]) return;
33     bel[x]=cnt;
34     ans+=val[mx[x]]*a[x];
35     chmin(mn,val[mx[x]]-val[sc[x]]);
36     if(mx[x]!=x)dfs(mx[x]);
37 }
38 signed main(){
39     freopen("goods.in","r",stdin);
40     freopen("goods.out","w",stdout);
41     n=read();
42     for(int i=1;i<=n;i++)
43         f[i]=read(), c[i]=read(), d[i]=read(), a[i]=read();
44     for(int i=1;i<=n;i++){
45         val[i]=d[f[i]]-c[i];
46         if(val[i]>val[mx[f[i]]]) sc[f[i]]=mx[f[i]], mx[f[i]]=i;
47         else if(val[i]>val[sc[f[i]]]) sc[f[i]]=i;
48     }
49     for(int i=1;i<=n;i++)
50         if(!bel[i]) ++cnt,mn=INT_MAX,dfs(i);
51     write(ans,'\n');
52     return 0;
53 }
T1

T2 ZYB玩字符串


可以想到暴力枚举子串暴力删除$check$,但假了,因为删除顺序可能导致结果不同。

考虑$DP$来$check$。设$f_{l,r}$表示母串$s$内$l$到$r$区间内的串能否被选出的子串$p$匹配。如果$r-l+1$不是$|p|$的倍数,那么要求剩余部分拼成$p$的前缀。

有转移:

$f_{l,r}|=f_{l,r-1}\text{&}[s_r=q_{(l-r)\textit{ mod }|p|+1}]$

$f_{l,r}|=f_{l,r-k\times |p|}\text{&}f_{t-k\times |p|+1,r}$

可以用字符集出现次数的$gcd$剪枝,跑得很快(其实还能记忆化,会更快

$code:$

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 
  4 namespace IO{
  5     inline int read(){
  6         char ch=getchar(); int x=0,f=1;
  7         while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
  8         while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
  9         return x*f;
 10     }
 11     inline void write(int x,char sp){
 12         char ch[20]; int len=0;
 13         if(x<0){ putchar('-'); x=~x+1; }
 14         do{ ch[len++]=x%10+(1<<4)+(1<<5); x/=10; }while(x);
 15         for(int i=len-1;~i;--i) putchar(ch[i]); putchar(sp);
 16     }
 17     inline int max(int x,int y){ return x<y?y:x; }
 18     inline int min(int x,int y){ return x<y?x:y; }
 19     inline void swap(int &x,int &y){ x^=y^=x^=y; }
 20     inline void chmax(int &x,int y){ x=x<y?y:x; }
 21     inline void chmin(int &x,int y){ x=x<y?x:y; }
 22 } using namespace IO;
 23 
 24 const int NN=210;
 25 int T,n,g,hh,res,sah[30],has[30],apr[30],tms[30],f[NN][NN];
 26 char s[NN],tmp[NN],ans[NN];
 27 inline int gcd(int a,int b){ return !b?a:gcd(b,a%b); }
 28 
 29 void init(){
 30     hh=0; res=INT_MAX; ans[1]='z'+1;
 31     memset(apr,0,sizeof(apr)); memset(has,0,sizeof(has));
 32     for(int i=1;i<=n;i++){
 33         if(!has[s[i]-'a']) has[s[i]-'a']=++hh, sah[hh]=s[i]-'a';
 34         ++apr[has[s[i]-'a']];
 35     }
 36     g=gcd(apr[1],apr[2]);
 37     for(int i=3;i<=hh;i++) g=gcd(g,apr[i]);
 38     for(int i=1;i<=hh;i++) tms[i]=apr[i]/g;
 39 }
 40 bool begin(int l,int r){
 41     if(n%(r-l+1)) return 0;
 42     memset(apr,0,sizeof(apr));
 43     for(int i=l;i<=r;i++) ++apr[has[s[i]-'a']];
 44     for(int i=1;i<=hh;i++){
 45         if(!apr[i]) return 0;
 46         if(i>1&&apr[i]/tms[i]!=apr[i-1]/tms[i-1]) return 0;
 47     }
 48     return 1;
 49 }
 50 void upd(int l,int r){
 51     int len=r-l+1;
 52     for(int i=l;i<=r;i++) tmp[i-l+1]=s[i];
 53     if(len<res){
 54         res=len;
 55         for(int i=1;i<=len;i++) ans[i]=tmp[i];
 56         return;
 57     }
 58     if(len>res) return;
 59     for(int i=1;i<=len;i++){
 60         if(tmp[i]>ans[i]) return;
 61         if(tmp[i]<ans[i]){
 62             for(int j=1;j<=len;j++) ans[i]=tmp[i];
 63             return;
 64         }
 65     }
 66 }
 67 bool check(int l,int r){
 68     memset(f,0,sizeof(f));
 69     int len=r-l+1; f[l][r]=1;
 70     for(int i=l;i<=r;i++) tmp[i-l+1]=s[i];
 71     for(int i=1;i<=n-len+1;i++)
 72         if(s[i]==tmp[1]) f[i][i]=1;
 73     for(int i=2;i<=n;i++)
 74         for(int j=1;j<=n-i+1;j++){
 75             int x=j,y=j+i-1,ne=(i-1)%len+1;
 76             f[x][y]|=f[x][y-1]&(s[y]==tmp[ne]);
 77             for(int k=len;k<i;k+=len)
 78                 f[x][y]|=f[x][y-k]&f[y-k+1][y];
 79         }
 80     return f[1][n];
 81 }
 82 
 83 signed main(){
 84     freopen("string.in","r",stdin);
 85     freopen("string.out","w",stdout);
 86     T=read();
 87     while(T--){
 88         scanf("%s",s+1); n=strlen(s+1);
 89         init();
 90         for(int i=1;i<=n;i++){
 91             if(res!=INT_MAX) break;
 92             for(int j=i;j<=n;j++){
 93                 if(!begin(j-i+1,j)) continue;
 94                 if(check(j-i+1,j)) upd(j-i+1,j);
 95             }
 96         }
 97         for(int i=1;i<=res;i++) putchar(ans[i]);putchar('\n');
 98     }
 99     return 0;
100 }
T2

T3 午餐


神仙题,参考$DC$学长博客,讲得超清楚

$code:$

 1 #include<bits/stdc++.h>
 2 #define x first
 3 #define y second
 4 #define mp make_pair
 5 using namespace std;
 6 typedef pair<int,int> pii;
 7 
 8 namespace IO{
 9     inline int read(){
10         char ch=getchar(); int x=0,f=1;
11         while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
12         while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
13         return x*f;
14     }
15     inline void write(int x,char sp){
16         char ch[20]; int len=0;
17         if(x<0){ putchar('-'); x=~x+1; }
18         do{ ch[len++]=x%10+(1<<4)+(1<<5); x/=10; }while(x);
19         for(int i=len-1;~i;--i) putchar(ch[i]); putchar(sp);
20     }
21     inline int max(int x,int y){ return x<y?y:x; }
22     inline int min(int x,int y){ return x<y?x:y; }
23     inline void swap(int &x,int &y){ x^=y^=x^=y; }
24     inline void chmax(int &x,int y){ x=x<y?y:x; }
25     inline void chmin(int &x,int y){ x=x<y?x:y; }
26 } using namespace IO;
27 
28 const int NN=2e5+5,inf=0x3fffffff;
29 int n,m,u[NN],v[NN],L[NN],R[NN],is[NN],h[NN],f[NN];
30 int idx,to[NN<<1],nex[NN<<1],head[NN],l[NN<<1],r[NN<<1];
31 inline void add(int a,int b,int c,int d){
32     to[++idx]=b; nex[idx]=head[a]; head[a]=idx; l[idx]=c; r[idx]=d;
33     to[++idx]=a; nex[idx]=head[b]; head[b]=idx; l[idx]=c; r[idx]=d;
34 }
35 
36 void dij(){
37     priority_queue<pii,vector<pii>,greater<pii> >q;
38     for(int i=1;i<=n;i++)
39         if(is[i]==-1){
40             h[i]=inf;
41             q.push(mp(inf,i));
42         }
43     while(!q.empty()){
44         int x=q.top().y,y=q.top().x;
45         q.pop();
46         for(int i=head[x];i;i=nex[i]){
47             int vv=to[i];
48             if(h[x]>=r[i]&&h[vv]<l[i]){
49                 h[vv]=l[i];
50                 q.push(mp(h[vv],vv));
51             }
52         }
53     }
54     priority_queue<pii >qq; qq.push(mp(0,1));
55     for(int i=2;i<=n;i++) f[i]=inf;
56     while(!qq.empty()){
57         int x=qq.top().y,y=qq.top().x;
58         qq.pop();
59         for(int i=head[x];i;i=nex[i]){
60             int vv=to[i],val=max(h[vv]+1,max(f[x],l[i]));
61             if(f[vv]>val&&val<=r[i]){
62                 f[vv]=val;
63                 qq.push(mp(f[vv],vv));
64             }
65         }
66     }
67 }
68 
69 signed main(){
70     freopen("lunch.in","r",stdin);
71     freopen("lunch.out","w",stdout);
72     n=read(); m=read();
73     for(int i=1;i<=m;i++){
74         u[i]=read(),v[i]=read(),L[i]=read(),R[i]=read();
75         add(u[i],v[i],L[i],R[i]);
76     }
77     for(int i=1;i<=n;i++) is[i]=read();
78     dij();
79     if(h[1]){ puts("Impossible"); return 0; }
80     for(int i=1;i<=n;i++) if(is[i]==1&&f[i]==inf){ puts("Impossible"); return 0; }
81     for(int i=1;i<=m;i++)
82         if(f[u[i]]<=R[i]&&f[v[i]]<=R[i]) chmax(L[i],max(f[u[i]],f[v[i]]));
83     for(int i=1;i<=m;i++) write(L[i],'\n');
84     return 0;
85 }
T4

T4 计数


前序遍历中编号满足$a<b$,只有两种情况:

$1$.$a$是$b$的祖先

$2$.$a$在$LCA$的左子树,$b$在$LCA$的右子树。

考虑加限制,强制令前序遍历中$a<b$,那么中序遍历中:

$1$.$a$在$b$前,那么$b$只能在$a$的右子树或是上面第二种情况,可以总结为$b$不在$a$

$2$.$a$在$b$后,那么$b$只能在$a$的左子树中。

两种限制对$a$的左子树大小都有要求,$1$要求大小小于$b-a$,$2$要求大小不小于$b-a$。

于是可以求出$a$左子树大小范围,考虑$DP$。

$f_{i,j}$表示$i$子树大小为$j$的方案,有:

$f_{i,j}=\sum_kf_{i+1,k}\times f_{i+k+1,i-k-1}$,$k$为$i$可行的左子树大小。

$code:$

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 
 5 namespace IO{
 6     inline int read(){
 7         char ch=getchar(); int x=0,f=1;
 8         while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
 9         while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
10         return x*f;
11     }
12     inline void write(int x,char sp){
13         char ch[20]; int len=0;
14         if(x<0){ putchar('-'); x=~x+1; }
15         do{ ch[len++]=x%10+(1<<4)+(1<<5); x/=10; }while(x);
16         for(int i=len-1;~i;--i) putchar(ch[i]); putchar(sp);
17     }
18     inline int max(int x,int y){ return x<y?y:x; }
19     inline int min(int x,int y){ return x<y?x:y; }
20     inline void swap(int &x,int &y){ x^=y^=x^=y; }
21     inline void chmax(int &x,int y){ x=x<y?y:x; }
22     inline void chmin(int &x,int y){ x=x<y?x:y; }
23 } using namespace IO;
24 
25 const int NN=405,p=1e9+7;
26 int t,n,m,u,v,l[NN],r[NN],f[NN][NN];
27 
28 int dfs(int pos,int num){
29     if(f[pos][num]!=-1) return f[pos][num];
30     if(pos>n||!num) return f[pos][num]=1;
31     if(num>n-pos+1||num<l[pos]) return f[pos][num]=0;
32     int up=min(num-1,r[pos]); f[pos][num]=0;
33     for(int i=l[pos];i<=up;i++)
34         (f[pos][num]+=dfs(pos+1,i)*dfs(pos+i+1,num-i-1)%p)%=p;
35     return f[pos][num];
36 }
37 
38 signed main(){
39 //    freopen("count.in","r",stdin);
40 //    freopen("count.out","w",stdout);
41     t=read();
42     while(t--){
43         n=read(); m=read();
44         memset(f,-1,sizeof(f));
45         for(int i=1;i<=n;i++)
46             l[i]=0, r[i]=n-i;
47         for(int i=1;i<=m;i++){
48             u=read(), v=read();
49             if(u<v) chmin(r[u],v-u-1);
50             else chmax(l[v],u-v);
51         }
52         write(dfs(1,n),'\n');
53     }
54     return 0;
55 }
T4

 

posted @ 2021-09-15 07:52  keen_z  阅读(34)  评论(0编辑  收藏  举报