ACM-ICPC 2018 焦作赛区网络预赛 做题记录

本文深入解析了ACM竞赛中的经典算法题目,包括字符串匹配、动态规划、树链剖分、最大费用流、后缀自动机等高级算法的实现与应用,通过实战案例帮助读者掌握算法精髓。

今天H题真的有毒,居然不放单组数据范围……SAM卡了半天空间打死过不去

J题卡牛顿迭代常数也是很那啥的

补题进度:10/12

A.

签到题,模拟

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int T;
 4 int main()
 5 {
 6     scanf("%d",&T);
 7     while(T--)
 8     {
 9         string s;
10         cin>>s;
11         for(int i=0;i<s.length();++i)
12         {
13             if('A'<=s[i]&&s[i]<='Z')s[i]=s[i]-'A'+'a';
14         }
15         if(s=="jessie")puts("Good guy!");
16         else puts("Dare you say that again?");
17     }
18     return 0;
19 }

 

B.

dp,维护最大值和最小值,互相转移

注意一下边界条件

 1 #include<bits/stdc++.h>
 2 #define maxn 2005
 3 #define inf 1e17
 4 #define ll long long
 5 using namespace std;
 6 int T,n,m,k;
 7 ll a[maxn];
 8 char b[8];
 9 ll f[8][maxn],g[8][maxn];
10 int main()
11 {
12     scanf("%d",&T);
13     while(T--)
14     {
15         scanf("%d%d%d",&n,&m,&k);
16         for(int i=1;i<=n;++i)scanf("%lld",&a[i]);
17         scanf("%s",b+1);
18         for(int i=0;i<=n;++i)f[0][i]=g[0][i]=k;
19         ll ans=-inf;
20         for(int i=1;i<=m;++i)
21         {
22             for(int j=i;j<=n;++j)
23             {
24                 if(b[i]=='+')
25                 {
26                     f[i][j]=f[i-1][j-1]+a[j];
27                     g[i][j]=g[i-1][j-1]+a[j];
28                 }
29                 if(b[i]=='-')
30                 {
31                     f[i][j]=f[i-1][j-1]-a[j];
32                     g[i][j]=g[i-1][j-1]-a[j];
33                 }
34                 if(b[i]=='*')
35                 {
36                     f[i][j]=max(f[i-1][j-1]*a[j],g[i-1][j-1]*a[j]);
37                     g[i][j]=min(f[i-1][j-1]*a[j],g[i-1][j-1]*a[j]);
38                 }
39                 if(b[i]=='/')
40                 {
41                     f[i][j]=max(f[i-1][j-1]/a[j],g[i-1][j-1]/a[j]);
42                     g[i][j]=min(f[i-1][j-1]/a[j],g[i-1][j-1]/a[j]);
43                 }
44                 if(j>i)
45                 {
46                     f[i][j]=max(f[i][j],f[i][j-1]);
47                     g[i][j]=min(g[i][j],g[i][j-1]);
48                 }
49             }
50         }
51         cout<<f[m][n]<<endl;
52     }
53     return 0;
54 }

 

G.

打表找规律,发现是2^(n-1),欧拉定理指数取模一下

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 #define maxn 1000005
 4 using namespace std;
 5 const ll mod=1000000007;
 6 int T;
 7 char s[maxn];
 8 ll fastpow(ll a,ll p)
 9 {
10     ll ans=1;
11     while(p)
12     {
13         if(p&1)ans=ans*a%mod;
14         a=a*a%mod;
15         p>>=1;
16     }
17     return ans;
18 }
19 int main()
20 {
21     scanf("%d",&T);
22     while(T--)
23     {
24         scanf("%s",s+1);
25         ll n=0,len=strlen(s+1);
26         for(int i=1;i<=len;++i)n=n*10+s[i]-'0',n%=(mod-1);
27         n=(n-1+(mod-1))%(mod-1);
28         ll ans=fastpow(2,n);
29         cout<<ans<<endl;
30     }
31     return 0;
32 }

 

E.

显然树链剖分,然后加和乘用双标记线段树维护

考虑取模意义下取反操作,bitwise not x=2^64-1-x=-1-x=(-1)*(x+1)=(2^64-1)*x+(2^64-1)

然后就变成了加和乘操作

mod 2^64 用unsigned long long的自然溢出就行了

  1 #include<bits/stdc++.h>
  2 #define ll unsigned long long
  3 #define maxn 100005
  4 const ll maxf=(ll)18446744073709551615;
  5 using namespace std;
  6 int n,q;
  7 vector<int> g[maxn];
  8 int d[maxn],fa[maxn],size[maxn],wson[maxn];
  9 void dfs1(int u)
 10 {
 11     size[u]=1;wson[u]=0;
 12     for(int i=0;i<g[u].size();++i)
 13     {
 14         int v=g[u][i];
 15         d[v]=d[u]+1;fa[v]=u;
 16         dfs1(v);
 17         size[u]+=size[v];
 18         if(size[v]>size[wson[u]])wson[u]=v;
 19     }
 20 }
 21 int top[maxn],lpos[maxn],cnt;
 22 void dfs2(int u,int TOP)
 23 {
 24     top[u]=TOP;
 25     lpos[u]=++cnt;
 26     if(wson[u])dfs2(wson[u],TOP);
 27     for(int i=0;i<g[u].size();++i)
 28     {
 29         int v=g[u][i];
 30         if(v==wson[u])continue;
 31         dfs2(v,v);
 32     }
 33 }
 34 ll sumv[maxn<<2],addv[maxn<<2],mulv[maxn<<2];
 35 void pushup(int rt)
 36 {
 37     sumv[rt]=sumv[rt<<1]+sumv[rt<<1|1];
 38 }
 39 void pushdown(int rt,int l,int r)
 40 {
 41     int mid=(l+r)>>1;
 42     if(mulv[rt]!=1)
 43     {
 44         ll t=mulv[rt];
 45         sumv[rt<<1]*=t;sumv[rt<<1|1]*=t;
 46         addv[rt<<1]*=t;addv[rt<<1|1]*=t;
 47         mulv[rt<<1]*=t;mulv[rt<<1|1]*=t;
 48         mulv[rt]=1;
 49     }
 50     if(addv[rt])
 51     {
 52         ll t=addv[rt];
 53         sumv[rt<<1]+=t*(mid-l+1);sumv[rt<<1|1]+=t*(r-mid);
 54         addv[rt<<1]+=t;addv[rt<<1|1]+=t;
 55         addv[rt]=0;
 56     }
 57 }
 58 void build(int rt,int l,int r)
 59 {
 60     sumv[rt]=0;addv[rt]=0;mulv[rt]=1;
 61     if(l==r)
 62     {
 63         return;
 64     }
 65     int mid=(l+r)>>1;
 66     build(rt<<1,l,mid);build(rt<<1|1,mid+1,r);
 67     pushup(rt);
 68 }
 69 void add(int rt,int l,int r,int ql,int qr,ll v)
 70 {
 71     int mid=(l+r)>>1;
 72     if(ql<=l&&r<=qr)
 73     {
 74         sumv[rt]+=v*(r-l+1);addv[rt]+=v;
 75         return;
 76     }
 77     pushdown(rt,l,r);
 78     if(ql<=mid)add(rt<<1,l,mid,ql,qr,v);
 79     if(qr>mid)add(rt<<1|1,mid+1,r,ql,qr,v);
 80     pushup(rt);
 81 }
 82 void mul(int rt,int l,int r,int ql,int qr,ll v)
 83 {
 84     int mid=(l+r)>>1;
 85     if(ql<=l&&r<=qr)
 86     {
 87         sumv[rt]*=v;addv[rt]*=v;mulv[rt]*=v;
 88         return;
 89     }
 90     pushdown(rt,l,r);
 91     if(ql<=mid)mul(rt<<1,l,mid,ql,qr,v);
 92     if(qr>mid)mul(rt<<1|1,mid+1,r,ql,qr,v);
 93     pushup(rt);
 94 }
 95 ll query(int rt,int l,int r,int ql,int qr)
 96 {
 97     int mid=(l+r)>>1;
 98     if(ql<=l&&r<=qr)return sumv[rt];
 99     pushdown(rt,l,r);
100     ll ans=0;
101     if(ql<=mid)ans+=query(rt<<1,l,mid,ql,qr);
102     if(qr>mid)ans+=query(rt<<1|1,mid+1,r,ql,qr);
103     pushup(rt);
104     return ans;
105 }
106 void add(int u,int v,ll w)
107 {
108     while(top[u]!=top[v])
109     {
110         if(d[top[u]]<d[top[v]])swap(u,v);
111         add(1,1,n,lpos[top[u]],lpos[u],w);
112         u=fa[top[u]];
113     }
114     if(d[u]<d[v])swap(u,v);
115     add(1,1,n,lpos[v],lpos[u],w);
116 }
117 void mul(int u,int v,ll w)
118 {
119     while(top[u]!=top[v])
120     {
121         if(d[top[u]]<d[top[v]])swap(u,v);
122         mul(1,1,n,lpos[top[u]],lpos[u],w);
123         u=fa[top[u]];
124     }
125     if(d[u]<d[v])swap(u,v);
126     mul(1,1,n,lpos[v],lpos[u],w);
127 }
128 ll query(int u,int v)
129 {
130     ll ans=0;
131     while(top[u]!=top[v])
132     {
133         if(d[top[u]]<d[top[v]])swap(u,v);
134         ans+=query(1,1,n,lpos[top[u]],lpos[u]);
135         u=fa[top[u]];
136     }
137     if(d[u]<d[v])swap(u,v);
138     ans+=query(1,1,n,lpos[v],lpos[u]);
139     return ans;
140 }
141 int main()
142 {
143     while(~scanf("%d",&n))
144     {
145         for(int i=1;i<=n;++i)g[i].clear(),fa[i]=0,d[i]=0;
146         cnt=0;
147         for(int i=2;i<=n;++i)
148         {
149             int x;scanf("%d",&x);
150             g[x].push_back(i);
151         }
152         d[1]=1;
153         dfs1(1);dfs2(1,1);
154         build(1,1,n);
155         scanf("%d",&q);
156         while(q--)
157         {
158             int opt,u,v;ll x;
159             scanf("%d%d%d",&opt,&u,&v);
160             if(opt<=2)scanf("%llu",&x);
161             if(opt==1)
162             {
163                 mul(u,v,x);
164             }
165             if(opt==2)
166             {
167                 add(u,v,x);
168             }
169             if(opt==3)
170             {
171                 mul(u,v,maxf);
172                 add(u,v,maxf);
173             }
174             if(opt==4)
175             {
176                 printf("%llu\n",query(u,v));
177             }
178         }
179     }
180     return 0;
181 }

 

F.

裸的区间k覆盖,最大费用流

连边:(i,i+1,k,0),(a[i],b[i]+1,1,-w),(s,1,k,0),(n+1,t,k,0)

(居然卡常数,拆点的费用流被卡掉了,只能(a[i]->b[i]+1)连边)

 1 #include<bits/stdc++.h>
 2 #define inf 1000000000
 3 #define maxn 805
 4 using namespace std;
 5 int T;
 6 int n,m,k;
 7 int a[maxn],b[maxn],w[maxn];
 8 int c[maxn];
 9 int head[maxn],p,s,t;
10 struct edge
11 {
12     int from,to,next,f,c;
13 }e[maxn*10];
14 void addedge(int u,int v,int f,int c)
15 {
16     e[p].from=u;e[p].to=v;e[p].f=f;e[p].c=c;e[p].next=head[u];head[u]=p++;
17     e[p].from=v;e[p].to=u;e[p].f=0;e[p].c=-c;e[p].next=head[v];head[v]=p++;
18 }
19 int dis[maxn],inq[maxn],pre[maxn];
20 bool vis[maxn];
21 bool spfa(int s,int t)
22 {
23     memset(inq,0,sizeof(inq));
24     memset(pre,-1,sizeof(pre));
25     queue<int> q;
26     for(int i=s;i<=t;i++)dis[i]=inf;dis[s]=0;
27     q.push(s);inq[s]=1;
28     while(!q.empty())
29     {
30         int u=q.front();q.pop();inq[u]=0;
31         for(int i=head[u];i!=-1;i=e[i].next)
32         {
33             int v=e[i].to,f=e[i].f,c=e[i].c;
34             if(f&&dis[v]>dis[u]+c)
35             {
36                 dis[v]=dis[u]+c;pre[v]=i;
37                 if(!inq[v])inq[v]=1,q.push(v);
38             }
39         }
40     }
41     return dis[t]!=inf;
42 }
43 int dfs(int u,int maxf,int t)
44 {
45     if(u==t)return maxf;int tmp=0;
46     vis[u]=1;
47     for(int i=head[u];i!=-1&&tmp<maxf;i=e[i].next)if(!vis[e[i].to])
48     {
49         int v=e[i].to,f=e[i].f,c=e[i].c;
50         if(f&&dis[v]==dis[u]+c)
51         {
52             int minn=min(maxf-tmp,f);
53             f=dfs(v,minn,t);tmp+=f;e[i].f-=f;e[i^1].f+=f;
54         }
55     }
56     return tmp;
57 }
58 int mcmf(int s,int t)
59 {
60     int ans=0;
61     while(spfa(s,t))
62     {
63         memset(vis,0,sizeof(vis));
64         ans+=dfs(s,inf,t)*dis[t];
65     }
66     return ans;
67 }
68 int main()
69 {
70     scanf("%d",&T);
71     while(T--)
72     {
73         scanf("%d%d%d",&n,&k,&m);
74         for(int i=1;i<=m;++i)
75         {
76             scanf("%d%d%d",&a[i],&b[i],&w[i]);
77             c[2*i-1]=a[i];c[2*i]=b[i];
78         }
79         sort(c+1,c+2*m+1);
80         n=unique(c+1,c+2*m+1)-c-1;
81         p=0;
82         memset(head,-1,sizeof(head));
83         s=0;t=n+2;
84         for(int i=1;i<=m;++i)
85         {
86             a[i]=lower_bound(c+1,c+n+1,a[i])-c;
87             b[i]=lower_bound(c+1,c+n+1,b[i])-c;
88         }
89         for(int i=1;i<=n;++i)addedge(i,i+1,k,0);
90         for(int i=1;i<=m;++i)addedge(a[i],b[i]+1,1,-w[i]);
91         addedge(s,1,k,0);
92         addedge(n+1,t,k,0);
93         int ans=abs(mcmf(s,t));
94         printf("%d\n",ans);
95     }
96     return 0;
97 }

 

H.

后缀自动机裸题,统计right集合大小在[A,B]之间的,每次maxlen[u]-minlen[u]+1就行

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 #define maxn 200005
 4 using namespace std;
 5 int ch[maxn][26];
 6 int fa[maxn],cnt,last,rt;
 7 ll sz[maxn],dis[maxn];
 8 void init()
 9 {
10     cnt=0;
11     rt=last=++cnt;
12     memset(fa,0,sizeof(fa));
13     memset(dis,0,sizeof(dis));
14     memset(sz,0,sizeof(sz));
15     memset(ch,0,sizeof(ch));
16 }
17 inline int newnode(int x){dis[++cnt]=x;return cnt;}
18 void add(int x)
19 {
20     int np=newnode(dis[last]+1),p=last;
21     for(;p&&(!ch[p][x]);p=fa[p])ch[p][x]=np;
22     if(!p)fa[np]=rt;
23     else
24     {
25         int q=ch[p][x];
26         if(dis[q]==dis[p]+1)fa[np]=q;
27         else
28         {
29             int nq=newnode(dis[p]+1);
30             memcpy(ch[nq],ch[q],sizeof(ch[q]));
31             fa[nq]=fa[q];
32             fa[q]=fa[np]=nq;
33             for(;ch[p][x]==q;p=fa[p])ch[p][x]=nq;
34         }
35     }
36     last=np;
37     sz[np]=1;
38 }
39 char s[maxn];
40 int A,B;
41 int c[maxn],t[maxn];
42 ll count()
43 {
44     memset(c,0,sizeof(c));
45     memset(t,0,sizeof(t));
46     ll ans=0;
47     for(int i=1;i<=cnt;i++)c[dis[i]]++;
48     for(int i=1;i<=cnt;i++)c[i]+=c[i-1];
49     for(int i=cnt;i;i--)t[c[dis[i]]--]=i;
50     for(int i=cnt;i;i--){int x=t[i];sz[fa[x]]+=sz[x];}
51     for(int i=2;i<=cnt;++i)if(A<=sz[i]&&sz[i]<=B)ans+=dis[i]-dis[fa[i]];
52     return ans;
53 }
54 int main()
55 {
56     while(~scanf("%s%d%d",s+1,&A,&B))
57     {
58         init();
59         for(int i=1;s[i];++i)add(s[i]-'A');
60         cout<<count()<<endl;
61     }
62     return 0;
63 }

 

I.

观察一下,三个都是奇数显然不行,否则显然可以

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int a,b,c; 
 4 int main()
 5 {
 6     while(~scanf("%d%d%d",&a,&b,&c))
 7     {
 8         if((a&1)&&(b&1)&&(c&1))puts("No");
 9         else puts("Yes");
10     }
11     return 0;
12 }

 

J.

牛顿迭代打死卡不过去,跑1.5s

学习了一波二次剩余的姿势

若x^2=n(mod p),则pow(n,(p-1)/2)=1(mod p)

然后我们选一些大质数判一判就好了

 1 #include<bits/stdc++.h>
 2 #define maxn 205
 3 #define ll long long
 4 using namespace std;
 5 int T;
 6 const ll M[11]={1000000181,1000000007,1000000009,998244353,1000000021,1000000087,1000000223,1000000241,1000000579,1000000531,1000000607};
 7 char str[maxn];
 8 ll fastpow(ll a,ll p,ll mod)
 9 {
10     ll ans=1;
11     while(p)
12     {
13         if(p&1)ans=ans*a%mod;
14         a=a*a%mod;p>>=1;
15     }
16     return ans;
17 }
18 int main()
19 {
20     scanf("%d",&T);
21     while(T--)
22     {
23         scanf("%s",str+1);
24         int len=strlen(str+1);
25         if(len==1&&str[1]=='1')
26         {
27             puts("Arena of Valor");
28             continue;
29         }
30         bool yes1=1,yes2=1;
31         for(int i=0;i<=10;++i)
32         {
33             ll mod=M[i];
34             ll n=0;
35             for(int j=1;j<=len;++j)n=n*10+str[j]-'0',n%=mod;
36             ll m=(n-1+mod)%mod;
37             ll res=n*m%mod*fastpow(2,mod-2,mod)%mod;
38             ll x=fastpow(res,(mod-1)/2,mod);
39             if(x!=1)yes1=0;
40             ll y=fastpow(n,(mod-1)/2,mod);
41             if(y!=1)yes2=0;
42         }
43         if(yes1&&yes2)
44         {
45             puts("Arena of Valor");
46         }
47         else if((yes1)&&(!yes2))
48         {
49             puts("Clash Royale");
50         }
51         else if((!yes1)&&(yes2))
52         {
53             puts("Hearth Stone");
54         }
55         else if((!yes1)&&(!yes2))
56         {
57             puts("League of Legends");
58         }
59     }
60     return 0;
61 } 

 

K.

多重背包计数,暴力dp为O(N*S*S)的

考虑把转移中的O(S)优化掉:

如果没有c[i]限制,那么每次记录 mod v[i]意义下分类的总和,每次加上总和即可

现在有了c[i]限制,考虑mod v[i]意义下是连续的一段转移过来的,所以用滑动窗口维护下就行了

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 #define maxn 22
 4 #define maxc 10005
 5 using namespace std;
 6 const ll mod=1000000007;
 7 int T,n,q;
 8 ll v[maxn],c[maxn];
 9 ll dp[maxn][maxc],tmp[maxn];
10 queue<ll> que[maxn];
11 int main()
12 {
13     scanf("%d",&T);
14     while(T--)
15     {
16         memset(dp,0,sizeof(dp));
17         scanf("%d%d",&n,&q);
18         for(int i=1;i<=n;++i)scanf("%lld%lld",&v[i],&c[i]);
19         dp[0][0]=1;
20         for(int i=1;i<=n;++i)
21         {
22             memset(tmp,0,sizeof(tmp));
23             for(int i=0;i<=20;++i)while(!que[i].empty())que[i].pop(); 
24             for(int j=0;j<=10000;++j)
25             {
26                 tmp[j%v[i]]+=dp[i-1][j];
27                 tmp[j%v[i]]%=mod;
28                 if(j>=((1<<c[i]))*v[i])tmp[j%v[i]]-=que[j%v[i]].front(),que[j%v[i]].pop(),tmp[j%v[i]]=(tmp[j%v[i]]%mod+mod)%mod;
29                 que[j%v[i]].push(dp[i-1][j]);
30                 dp[i][j]+=tmp[j%v[i]];dp[i][j]%=mod;
31             }
32         }
33         while(q--)
34         {
35             int s;
36             scanf("%d",&s);
37             printf("%d\n",(int)dp[n][s]);
38         }
39     }
40     return 0;
41 }

 

L.

dp;

f(i,j,k)表示现在是第i天,状态为j(0/1/2),上一天状态为k(0/1/2)

f(i,0,0)=f(i-1,0,1)+f(i-1,0,2);
f(i,0,1)=f(i-1,1,0)+f(i-1,1,1)+f(i-1,1,2);
f(i,0,2)=f(i-1,2,0)+f(i-1,2,2);
f(i,1,0)=f(i,0,1);
f(i,1,1)=f(i,0,0);
f(i,1,2)=f(i,0,2);
f(i,2,0)=f(i-1,0,0)+f(i-1,0,1);
f(i,2,1)=f(i,2,0);
f(i,2,2)=f(i-1,2,0)+f(i-1,2,1);

然后发现都是线性齐次递推,直接构造9*9的矩阵,上矩阵快速幂

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 const ll mod=1000000007;
 5 int T;
 6 ll n;
 7 const int m=9;
 8 struct Matrix
 9 {
10     ll a[25][25];
11     void clear(){memset(a,0,sizeof(a));}
12     void init(){memset(a,0,sizeof(a));for(int i=1;i<=m;i++)a[i][i]=1;}
13 };
14 Matrix operator * (Matrix a,Matrix b)
15 {
16     Matrix c;c.clear();
17     for(int i=1;i<=m;i++)
18     for(int j=1;j<=m;j++)
19     for(int k=1;k<=m;k++)
20     c.a[i][j]+=a.a[i][k]*b.a[k][j]%mod,c.a[i][j]%=mod;
21     return c;
22 }
23 Matrix fastpow(Matrix a,ll p)
24 {
25     Matrix ans;ans.init();
26     for(;p;p>>=1,a=a*a)if(p&1)ans=ans*a;
27     return ans;
28 }
29 int main()
30 {
31     cin>>T;
32     while(T--)
33     {
34         cin>>n;
35         if(n==1)
36         {
37             puts("3");
38             continue;
39         }
40         Matrix A;A.clear();
41         A.a[1][2]=A.a[1][3]=A.a[2][4]=A.a[2][5]=A.a[2][6]=A.a[3][7]=A.a[3][9]=A.a[4][4]=A.a[4][5]=A.a[4][6]=1;
42         A.a[5][2]=A.a[5][3]=A.a[6][7]=A.a[6][9]=A.a[7][1]=A.a[7][2]=A.a[8][1]=A.a[8][2]=A.a[9][7]=A.a[9][8]=1;
43         Matrix res=fastpow(A,n-2);
44         Matrix tmp;tmp.clear();
45         for(int i=1;i<=9;++i)tmp.a[i][1]=1;
46         Matrix R=res*tmp;
47         ll ans=0;
48         for(int i=1;i<=9;++i)ans+=R.a[i][1];
49         ans%=mod;
50         cout<<ans<<endl;
51     }
52     return 0;
53 }

 

转载于:https://www.cnblogs.com/uuzlove/p/9651700.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值