2023ICPC合肥题解
文章目录
- F. Colorful Balloons(签到)
- E. Matrix Distances(思维+小结论)
- J. Takeout Delivering(最短路)
- G. Streak Manipulation(二分+dp)
- C. Cyclic Substrings(回文自动机)
题目链接
F. Colorful Balloons(签到)
int n;cin>>n;for(int i=1;i<=n;i++) cin>>s[i];map<string,int> mp;for(int i=1;i<=n;i++){mp[s[i]]++;if(mp[s[i]]*2 > n){cout<<s[i];return;}}cout<<"uh-oh";
E. Matrix Distances(思维+小结论)
经典的x和y可以分开算
int n,m;cin>>n>>m;vector<int> nums;for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){cin>>c[i][j];nums.push_back(c[i][j]);}sort(nums.begin(),nums.end());nums.erase(unique(nums.begin(),nums.end()),nums.end());for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){c[i][j]=lower_bound(nums.begin(),nums.end(),c[i][j])-nums.begin();}}int ans=0;vector<int> num(nums.size()+1),sum(nums.size()+1);for(int j=1;j<=m;j++) //for(int i=1;i<=n;i++){ans+=num[c[i][j]]*j - sum[c[i][j]];sum[c[i][j]]+=j;num[c[i][j]]++;}for(int i=0;i<nums.size()+1;i++)num[i]=sum[i]=0;for(int i=1;i<=n;i++) //for(int j=1;j<=m;j++){ans+=num[c[i][j]]*i - sum[c[i][j]];sum[c[i][j]]+=i;num[c[i][j]]++;}cout<<ans*2;
J. Takeout Delivering(最短路)
题意:
从 1 1 1走到 n n n,路径大小为最大的两条边的边权和
思路:
分别从 1 , n 1,n 1,n开始记录到每个点的最大值
枚举最大边,那么答案就是 min ( w + max ( d i s 1 , u , d i s v , n ) ) ( max ( d i s 1 , u , d i s v , n ) ≤ w ) \min (w+\max(dis_{1,u},dis_{v,n}))(\max(dis_{1,u},dis_{v,n}) \leq w) min(w+max(dis1,u,disv,n))(max(dis1,u,disv,n)≤w)
void solve(){int n,m;cin>>n>>m;vector<PII> adj[n+1];int ans=INF;vector<array<int,3>> e;for(int i=1;i<=m;i++){int u,v,w;cin>>u>>v>>w;if((u==1&&v==n)||(u==n&&v==1))ans=min(ans,w);adj[u].push_back({v,w});adj[v].push_back({u,w});e.push_back({u,v,w});}vector<int> vis(n+1);auto dijk=[&](vector<int> &dis,int st){priority_queue<PII,vector<PII>,greater<PII>> pq;dis[st]=0;vis.assign(n+1,0);pq.push({0,st});while(!pq.empty()){auto [d,u]=pq.top();pq.pop();if(vis[u])continue;vis[u]=1;for(auto [v,w]:adj[u]){int x=(dis[u]==0?w:max(dis[u],w));if(dis[v]>x){dis[v]=x;pq.push({dis[v],v});}}}};vector<int> dis1(n+1,INF),dis2(n+1,INF);dijk(dis1,1);dijk(dis2,n);for(auto [u,v,w]:e){if(dis1[u]<=w&&dis2[v]<=w)ans=min(ans,w+max(dis1[u],dis2[v]));if(dis1[v]<=w&&dis2[u]<=w)ans=min(ans,w+max(dis1[v],dis2[u]));}cout<<ans<<"\n";
}
G. Streak Manipulation(二分+dp)
给一个01字符串,问最大长度 l l l,这样的连续 1 1 1的不相连接线段至少有 k k k个,最多可以修改 m m m次 0 0 0变 1 1 1
很明显可以二分答案,并且 k k k很小可以直接dp
d p i , j dp_{i,j} dpi,j表示考虑完前 i i i个字母,构成了 j j j段长度为 l l l的线段,判断条件就是 d p n , k ≤ m dp_{n,k} \leq m dpn,k≤m
转移的时候我们枚举每个线段的合法右端点,然后获取大于等于 l l l的线段的左端点(这一部分最易出错,考虑各种边界即可,比如左右端点在原有的线段内,或者如果当前端点置1导致两个线段合并在一起不符和假设的左端点或右端点时,需要更新以下)
复杂度 O ( n log 2 n ) O(n \log^2n) O(nlog2n),实现好一点可以 O ( n log n ) O(n \log n) O(nlogn)
int n,m,k;
vector<PII> seg;
int sum[N];
bool check(int x){vector dp(n+1,vector<int>(k+1,INF));dp[0][0]=0;for(int i=1;i<=n;i++){for(int j=0;j<=k;j++)dp[i][j]=dp[i-1][j];auto it=upper_bound(seg.begin(),seg.end(),PII{i,INF});if(it!=seg.end()&&it->F-1==i)continue;if(it!=seg.begin()){it--;if(it->F<=i&&i<=it->S&&i!=it->S)continue;}int l=i-x+1;if(l<1)continue;it=upper_bound(seg.begin(),seg.end(),PII{l,INF});if(it!=seg.begin()){it--;if(l<=it->S+1)l=it->F;}int pos=l==1?0:l-2;for(int j=1;j<=k;j++){if(dp[pos][j-1]==INF)continue;dp[i][j]=min(dp[i][j],dp[pos][j-1]+sum[i]-sum[l-1]);}}return dp[n][k]<=m;
}
void solve(){cin>>n>>m>>k;string s;cin>>s;s=" "+s;for(int i=1;i<=n;i++)sum[i]=sum[i-1]+(s[i]=='0');for(int i=1,j;i<=n;i++){if(s[i]=='0')continue;j=i;while(j+1<=n&&s[j+1]==s[j])j++;seg.push_back({i,j});i=j;}int l=0,r=n;while(l<r){int mid=l+r+1>>1;if(check(mid))l=mid;else r=mid-1;}cout<<(l==0?-1:l);
}
C. Cyclic Substrings(回文自动机)
设 t t t为循环本质不同回文子串, f ( t ) f(t) f(t)表示出现次数, g ( t ) g(t) g(t)表示长度,求 ∑ f ( t ) 2 g ( t ) \sum f(t)^2g(t) ∑f(t)2g(t)
回文自动机板子题,令新串为 S = S S S=SS S=SS,那么就可以求出来 S S S的回文自动机,当前的回文串是有效的当下标 i > n i \gt n i>n
然后在fail树上做一遍累加,最后统计答案
struct PAM{static constexpr int ALPHABET_SIZE=10;struct Node{int len,link,cnt;// cnt表示以当前字符结尾的不同子串个数(视实际情况而定)array<int,ALPHABET_SIZE> next;};vector<Node> t;int suff;string s;PAM(){init();}void init(){t.assign(2,Node());t[0].len=-1;suff=1;s.clear();}int newNode(){t.emplace_back();return t.size()-1;}bool add(int c){int pos=s.size();s+=c;c=c-'0';int cur=suff,curlen=0;while(true){curlen=t[cur].len;if(pos-1-curlen>=0&&s[pos-1-curlen]==s[pos])break;cur=t[cur].link;}if(t[cur].next[c]){suff=t[cur].next[c];return false;}suff=newNode();t[suff].len=t[cur].len+2;t[cur].next[c]=suff;if(t[suff].len==1){t[suff].link=1;return true;}while(true){cur=t[cur].link;curlen=t[cur].len;if(pos-1-curlen>=0&&s[pos-1-curlen]==s[pos]){t[suff].link=t[cur].next[c];break;}}return true;}int next(int p,int c){return t[p].next[c-'0'];}int link(int p){return t[p].link;}int len(int p){return t[p].len;}int cnt(int p){return t[p].cnt;}int size(){return t.size();}
} pam;
void solve(){int n;cin>>n;string s;cin>>s;s+=s;auto &t=pam.t;for(int i=0;i<s.size();i++){pam.add(s[i]);if(i>n-1)t[pam.suff].cnt++;}for(int i=t.size()-1;i>=2;i--){t[t[i].link].cnt+=t[i].cnt;}LL ans=0;for(int i=2;i<t.size();i++){if(t[i].len<=n)ans+=1ll*t[i].cnt*t[i].cnt%mod*t[i].len%mod,ans%=mod;}cout<<ans<<"\n";
}