Codeforces Round #396 (Div. 2)

来源:互联网 发布:下载淘宝app下载 编辑:程序博客网 时间:2024/04/29 23:07

比赛链接:Codeforces Round #396 (Div. 2)

A:找最长不公共连续子序列。显然若s!=t,输出s和t最大长度,否则输出-1.

#include<bits/stdc++.h>using namespace std;typedef long long ll;int main(){string s,t;while(cin>>s>>t){if(s.length()>t.length())cout<<s.length()<<endl;else if(s.length()<t.length())cout<<t.length()<<endl;else if(s==t)cout<<-1<<endl;else cout<<s.length()<<endl;}return 0;}


B:题意是给定若干个线段长度,求能否从中选出三条线段组成一个三角形。

先将线段长度L排序,若长度为x,y,z的线段能组成三角形,显然z+y>x&&z-y<x  ,设y的下标为i,那么用L[i-1]来替代x,L[i+1]来替代z,显然条件仍前述条件仍满足。

因此可以得出结论:如果存在三条线段能组成三角形,那么在数组L中,必然存在连续的三条线段能组成三角形,那么我们检验就行。

#include<bits/stdc++.h>using namespace std;typedef long long ll;int l[100007];bool check(int a,int b,int c){if(a+b>c&&a+c>b&&b+c>a)return true;else return false;}int main(){int n;while(cin>>n){for(int i=0;i<n;i++)cin>>l[i];sort(l,l+n);int i;for(i=0;i<n-2;i++){if(check(l[i],l[i+1],l[i+2])){puts("YES");break;}}if(i==n-2)puts("NO");}return 0;}


C:题意是给定一个字符串,要求对字符串就行分割使得每对于每一个子串s,对于其中的每一个字符ch, a[ch]<=s.length() 。可以dp来做。

设dp[i]为串[0~i-1]能分割的方法数,len[i]为串[0~i-1]所能分割的最小子串数,并维护ans--整个串所能割出的最长子串的长度。

#include<bits/stdc++.h>using namespace std;typedef long long ll;const ll mod=1e9+7;ll dp[1007];int a[26],len[1007],cnt[26],ans;int f(char ch){return ch-'a';}bool check(int l){for(int i=0;i<26;i++)if(cnt[i]&&l>a[i])return false;return true;}int main(){int n;char s[1007];while(cin>>n){scanf("%s",s+1);for(int i=0;i<26;i++)cin>>a[i];memset(dp,0,sizeof(dp));for(int i=1;i<=n;i++)len[i]=1007;ans=dp[0]=1;len[0]=0;for(int i=1;i<=n;i++){memset(cnt,0,sizeof(cnt));for(int j=i;j>0;j--){cnt[f(s[j])]++;if(check(i-j+1)){dp[i]=(dp[i]+dp[j-1])%mod;ans=max(ans,i-j+1);len[i]=min(len[i],len[j-1]+1);}else break;}}cout<<dp[n]<<endl;cout<<ans<<endl;cout<<len[n]<<endl;}return 0;}


D:题意是给定一些词汇,并描述他们之间的关系,将矛盾的关系忽略。并且之后给定两个词,并查询他们之间的关系。

可以用并查集来做,词汇i的同义词是i,反义词是i+n,根据输入进行合并操作就行了。

#include<bits/stdc++.h>using namespace std;typedef long long ll;const int maxn=1e5+7;map<string,int> T;int father[maxn<<1];int f(int x){if(x==father[x])return x;father[x]=f(father[x]);return father[x];}void Union(int x,int y){x=f(x);y=f(y);father[x]=y;}int main(){ios::sync_with_stdio(false);int n,m,q;while(cin>>n>>m>>q){T.clear();int o;string s,t;for(int i=0;i<n;i++){cin>>s;T[s]=i;}for(int i=0;i<n*2;i++)father[i]=i;for(int i=0;i<m;i++){cin>>o>>s>>t;int l=T[s],r=T[t];if(o==1){if(f(l+n)==f(r)||f(r+n)==f(l))cout<<"NO"<<endl;else{Union(l,r);Union(l+n,r+n);cout<<"YES"<<endl;}}else{if(f(l+n)==f(r+n)||f(l)==f(r))cout<<"NO"<<endl;else{Union(l,r+n);Union(r,l+n);cout<<"YES"<<endl;}}}for(int i=0;i<q;i++){cin>>s>>t;int l=T[s],r=T[t];if(f(l)==f(r)||f(l+n)==f(r+n))cout<<1<<endl;else if(f(l)==f(r+n)||f(l+n)==f(r))cout<<2<<endl;else cout<<3<<endl;}}return 0;}


E:题意是给定一个带权树,求Sum(Xor(Path(i,j)))  {i<=j}。 Xor(Path(i,j))为 a_i^a_p_1^a_p_2^....a_p_k^a_j , 其中 i,p_1,p_2,...p_k,j为i到j的路径上一次经过的点。

对于每一个点的权值 val, val=Sum(bit[j]*(1<<j)) 。因此可以将每一位孤立出来进行求和。答案为Sum(ans[j]*(1<<j)) 。

因此可以来跑dfs并对每一位进行树形dp,记ans[j]为有第j为多少条路径的异或值为1,dp[i][j][k]为点i的第j位异或值为k的路径数(其中i必为一端点)。dp可以简单地通过其孩子的dp值来进行转移。

但i可能有多棵子树,假设u,v是i的不同子树中的结点,u,v也同样地构成路径。对于子树t, s为同根的其他子树。  x=使得Xor(t,root,s)=1的t和s对应异或值和位数j的路径数量之积。ans[j]+=x/2 。

要更容易理解的话,就是将每一位剖离出来单独进行一次dfs,然后把每一位dfs的值求和即可。最关键的就是要求出异或值为1的路径总数量

#include<bits/stdc++.h>using namespace std;typedef long long ll;ll dp[100007][23][2];ll ans[23];vector<int> adj[100007];int arr[100007][23];int dfs(int u,int p){ll t[23][2];memset(t,0,sizeof(t));for(int j=0;j<23;j++)dp[u][j][arr[u][j]]=1;for(int i=0;i<adj[u].size();i++){int v=adj[u][i];if(v==p)continue;dfs(v,u);for(int j=0;j<23;j++){for(int k=0;k<2;k++){dp[u][j][k]+=dp[v][j][k^arr[u][j]];t[j][k]+=dp[v][j][k];}}}for(int j=0;j<23;j++){ll x=0;for(int i=0;i<adj[u].size();i++){int v=adj[u][i];if(p==v)continue;for(int k=0;k<2;k++)x+=(t[j][k]-dp[v][j][k])*dp[v][j][1^k^arr[u][j]];}ans[j]+=x/2;}for(int j=0;j<23;j++)ans[j]+=dp[u][j][1];}int main(){ios::sync_with_stdio(false);int n,u,v;int a;cin>>n;for(int i=1;i<=n;i++){cin>>a;for(int j=0;j<23;j++){arr[i][j]=a&1;a>>=1;}}for(int i=1;i<n;i++){cin>>u>>v;adj[u].push_back(v);adj[v].push_back(u);}dfs(1,0);ll sum=0;for(int j=0;j<23;j++)sum+=(1<<j)*ans[j];cout<<sum<<endl;return 0;}


0 0
原创粉丝点击