988A.http://codeforces.com/contest/988/problem/A
题意:给出n个数,让你从中取出m个不同的数组成一组
分析:模拟即可。当每个人为第一次出现时,标记这个位置可取。最后从可取的位置取m个即可
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 using namespace std; 6 const int maxn=105; 7 int a[maxn]; 8 bool vis[maxn],used[maxn]; 9 10 int main() 11 { 12 int n,m,i,j,k,x,y,z,ans,cnt; 13 while ( scanf("%d%d",&n,&m)!=EOF ) 14 { 15 memset(vis,false,sizeof(vis)); 16 memset(used,false,sizeof(used)); 17 ans=cnt=0; 18 for ( i=1;i<=n;i++ ) 19 { 20 scanf("%d",&a[i]); 21 if ( !vis[a[i]] ) 22 { 23 vis[a[i]]=true; 24 used[i]=true; 25 ans++; 26 } 27 } 28 if ( m>ans ) printf("NO\n"); 29 else 30 { 31 printf("YES\n"); 32 for ( i=1;i<=n;i++ ) 33 { 34 if ( used[i] ) 35 { 36 printf("%d",i); 37 if ( ++cnt!=m ) printf(" "); 38 else printf("\n"); 39 } 40 if ( cnt==m ) break; 41 } 42 } 43 } 44 return 0; 45 }
A
988B.http://codeforces.com/contest/988/problem/B
题意:给出n个字符串,让你对字符串进行排序,使得前一个字符串是后一个字符串的字串
分析:以字符串长度为第一关键字,字符串的字典序为第二关键字进行排序。利用KMP(暴力应该也行)判断前一串是否为后一串的子串
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<string> 5 #include<iostream> 6 using namespace std; 7 const int maxn=110; 8 string s[maxn]; 9 10 int cmp(string a,string b) 11 { 12 if ( a.size()==b.size() ) return a<b; 13 return a.size()<b.size(); 14 } 15 16 int Next[maxn]; 17 char x[maxn],y[maxn]; 18 19 void pre_kmp(int m) 20 { 21 int i,j; 22 j=Next[0]=-1; 23 i=0; 24 while ( i<m ) { 25 while ( j!=-1 && x[i]!=x[j] ) j=Next[j]; 26 Next[++i]=++j; 27 } 28 } 29 30 bool kmp(int n,int m) 31 { 32 int i,j; 33 pre_kmp(m); 34 i=j=0; 35 while ( i<n ) { 36 while ( j!=-1 && y[i]!=x[j] ) j=Next[j]; 37 i++;j++; 38 if ( j>=m ) return true; 39 } 40 return false; 41 } 42 43 int main() 44 { 45 int n,i,j,k,z; 46 bool flag; 47 while ( scanf("%d",&n)!=EOF ) 48 { 49 for ( i=1;i<=n;i++ ) cin>>s[i]; 50 sort(s+1,s+1+n,cmp); 51 flag=true; 52 //for ( i=1;i<=n;i++ ) cout<<s[i]<<endl; 53 for ( i=1;i<n;i++ ) 54 { 55 int lenx=s[i].size(); 56 int leny=s[i+1].size(); 57 for ( j=0;j<lenx;j++ ) x[j]=s[i][j]; 58 for ( j=0;j<leny;j++ ) y[j]=s[i+1][j]; 59 if ( !kmp(leny,lenx) ) 60 { 61 flag=false; 62 break; 63 } 64 } 65 if ( !flag ) printf("NO\n"); 66 else { 67 printf("YES\n"); 68 for ( i=1;i<=n;i++ ) cout<<s[i]<<endl; 69 } 70 } 71 return 0; 72 }
B
988C.http://codeforces.com/contest/988/problem/C
题意:给定m个序列,第i个序列长度为ni。现在你可以从任意两个序列(不能是同一个)取出一个数,使得这两个序列剩下数字的和相等。求这两个序列的编号,和所取数的下标
分析:map<int,pair<int,int>>,first代表一个序列去掉一个数的和,second中的第一个代表是哪串序列,second中的第二个代表是该序列中哪个位置的数被取出。所以每次算出去掉一个数的和以后去找map中是否本来已经存在那个数即可
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<map> 5 using namespace std; 6 typedef pair<int,int>P; 7 const int maxn=2e5+10; 8 map<int,P>mp; 9 int a[maxn]; 10 11 int main() 12 { 13 int k,n,m,i,j,x,y,z,sum; 14 P p1,p2; 15 bool flag; 16 while ( scanf("%d",&m)!=EOF ) 17 { 18 mp.clear(); 19 flag=false; 20 for ( i=1;i<=m;i++ ) 21 { 22 scanf("%d",&n); 23 sum=0; 24 for ( j=1;j<=n;j++ ) 25 { 26 scanf("%d",&a[j]); 27 sum+=a[j]; 28 } 29 if ( flag ) continue; 30 for ( j=1;j<=n;j++ ) 31 { 32 k=sum-a[j]; 33 if ( mp.find(k)!=mp.end() ) 34 { 35 if ( mp[k].first==i ) continue; 36 else { 37 p1=mp[k]; 38 p2=P(i,j); 39 flag=true; 40 break; 41 } 42 } 43 else mp[k]=P(i,j); 44 if ( flag ) break; 45 } 46 } 47 if ( !flag ) printf("NO\n"); 48 else 49 { 50 printf("YES\n"); 51 printf("%d %d\n",p1.first,p1.second); 52 printf("%d %d\n",p2.first,p2.second); 53 } 54 } 55 return 0; 56 }
C
988D.http://codeforces.com/contest/988/problem/D
题意:给出一串长度为n的序列。现要从中取一个元素子集,使得该子集中任意两个数差的绝对值是2的倍数(1也算2的倍数),求子集中的元素最多有多少个
分析:由分析可得元素个数出现的可能只能是1 2 3。1的情况是任意两个数的差都不为2的倍数。2的情况存在两个数的差是2的倍数。三的情况是存在三个数a,b,c(假设a<b<c),满足d=b-a=c-a=2^x,即两两之间的差相等且是2的倍数。所以先预处理出2的倍数有哪些,然后将出现的数存入set中,对于每个数a去先求得b和c然后去找b和c在不在set中
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<set> 5 #include<cmath> 6 using namespace std; 7 typedef long long ll; 8 const int maxn=2e5+10; 9 ll a[maxn]; 10 ll num[70]; 11 set<ll>st; 12 13 int main() 14 { 15 ll n,m,i,j,k,x,y,z,ans,u,v,w; 16 bool flag; 17 while ( scanf("%lld",&n)!=EOF ) 18 { 19 st.clear(); 20 ans=1; 21 for ( i=0;i<=63;i++ ) num[i]=(pow(2,i)); 22 for ( i=1;i<=n;i++ ) 23 { 24 scanf("%lld",&a[i]); 25 st.insert(a[i]); 26 } 27 x=a[1]; 28 for ( i=1;i<=n;i++ ) 29 { 30 if ( ans==3 ) break; 31 m=a[i]; 32 for ( j=0;j<=62;j++ ) 33 { 34 35 u=m+num[j]; 36 v=m+num[j+1]; 37 if ( st.find(u)!=st.end() ) 38 { 39 ans=2; 40 x=a[i]; 41 y=u; 42 } 43 if ( st.find(u)!=st.end() && st.find(v)!=st.end() ) 44 { 45 ans=3; 46 x=a[i]; 47 y=u; 48 z=v; 49 break; 50 } 51 } 52 } 53 printf("%lld\n",ans); 54 if ( ans==1 ) printf("%lld\n",x); 55 else if ( ans==2 ) printf("%lld %lld\n",x,y); 56 else if ( ans==3 ) printf("%lld %lld %lld\n",x,y,z); 57 } 58 return 0; 59 }
D
988E.http://codeforces.com/contest/988/problem/E
题意:给出一个数n,现在可以交换相邻两个数,先求通过最少的交换次数使得得到的数是25的倍数(没有前导0),求最少的次数
分析:一个数是25的倍数那么这个是数的后两位一定是00,25,50,75这四种情况中的一种。那么我们只需要求出这四种情况所需要的次数,然后取最小值即可。
至于交换过程,我们需要让尽量右边的满足情况的数交换到相应的位置(贪心的思想)。同时注意不能出现前导0,如果第一个数是0的话,需要交换于从左到右第一个非0同时又不能是后两位的数进行交换
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<string> 5 #include<iostream> 6 using namespace std; 7 const int inf=1e9; 8 string t; 9 int n; 10 11 int cal(string nw) 12 { 13 string s=t; 14 int cnt=0; 15 for ( int i=n-1;i>=0;i-- ) 16 { 17 if ( s[i]==nw[1] ) 18 { 19 for ( int j=i;j+1<n;j++ ) 20 { 21 swap(s[j],s[j+1]); 22 cnt++; 23 } 24 break; 25 } 26 } 27 if ( s[n-1]!=nw[1] ) return inf; 28 for ( int i=n-2;i>=0;i-- ) 29 { 30 if ( s[i]==nw[0] ) 31 { 32 for ( int j=i;j+2<n;j++ ) 33 { 34 swap(s[j],s[j+1]); 35 cnt++; 36 } 37 break; 38 } 39 } 40 if ( s[n-2]!=nw[0] ) return inf; 41 if ( s[0]==‘0‘ ) 42 { 43 for ( int i=1;i<n-2;i++ ) 44 { 45 if ( s[i]!=‘0‘ ) 46 { 47 for ( int j=i;j>0;j-- ) 48 { 49 swap(s[j],s[j-1]); 50 cnt++; 51 } 52 break; 53 } 54 } 55 } 56 if ( s[0]==‘0‘ ) return inf; 57 else return cnt; 58 } 59 60 61 int main() 62 { 63 int i,j,k,ans; 64 while ( cin>>t ) 65 { 66 n=t.size(); 67 ans=inf; 68 ans=min(ans,cal("00")); 69 ans=min(ans,cal("25")); 70 ans=min(ans,cal("50")); 71 ans=min(ans,cal("75")); 72 if ( ans==inf ) printf("-1\n"); 73 else printf("%d\n",ans); 74 } 75 return 0; 76 }
E
988F.http://codeforces.com/contest/988/problem/F
题意:一个人要从0走到a,其中有n段会下雨,有m个点有伞(在有雨的地方必须要有伞,可以同时拿多把伞,伞可以随时放下,也可以随时拿起,同时一个点可能有多把伞),每个伞都有重量w,拿着伞走x距离会增加x*w的疲惫值,求走到a点最小的疲惫值
分析:普通的dp题。
法1:dp[i][j]表示从0到i时,在点i有第j把伞(没有伞时j==0)时的最小疲惫值。
转移时,分成三种情况(即对应着三种操作)
dp[i+1][j]=min(dp[i+1][j],dp[i][j]+w[j]) (第i+1个点下雨,同时没带伞时不成立,其他条件都成立) 该操作是从第i个点到第i+1个点啥也不做,即第i+1个点的状态和第i个点的状态相同
dp[i+1][0]=min(dp[i+1][0],dp[i][j]) (当下一个点没下雨时成立) 该操作是在第i个点放下伞
dp[i+1][id[i]]=min(dp[i+1][id[i]],dp[i][j]+w[id[i]]) (在第i个点有伞) 该操作是第i个点有伞,拿起伞走到第i+1个点上去
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 typedef long long ll; 6 typedef pair<int,int> P; 7 const int maxn=2010; 8 const int inf=1e9; 9 int dp[maxn][maxn],id[maxn]; 10 bool vis[maxn]; 11 P umb[maxn]; 12 13 int main() 14 { 15 int a,n,m,i,j,k,x,y,z,ans,l,r; 16 while ( scanf("%d%d%d",&a,&n,&m)!=EOF ) 17 { 18 memset(vis,false,sizeof(vis)); 19 memset(id,0,sizeof(id)); 20 for ( i=1;i<=n;i++ ) 21 { 22 scanf("%d%d",&l,&r); 23 for ( j=l+1;j<=r;j++ ) vis[j]=true; 24 } 25 for ( i=1;i<=m;i++ ) scanf("%d%d",&umb[i].first,&umb[i].second); 26 sort(umb+1,umb+1+m); 27 for ( i=1;i<=m;i++ ) { 28 if ( id[umb[i].first]==0) id[umb[i].first] = i; 29 } 30 umb[0].second=0; 31 for ( i=0;i<=a;i++ ) 32 { 33 for ( j=0;j<=m;j++ ) dp[i][j]=inf; 34 } 35 dp[0][0]=0; 36 for ( i=0;i<a;i++ ) 37 { 38 for ( j=0;j<=m;j++ ) 39 { 40 if ( j!=0 || !vis[i+1] ) dp[i+1][j]=min(dp[i+1][j],dp[i][j]+umb[j].second); 41 if ( !vis[i+1] ) dp[i+1][0]=min(dp[i+1][0],dp[i][j]); 42 if ( id[i] ) dp[i+1][id[i]]=min(dp[i+1][id[i]],dp[i][j]+umb[id[i]].second); 43 } 44 } 45 ans=inf; 46 for ( i=0;i<=m;i++ ) ans=min(dp[a][i],ans); 47 if ( ans!=inf ) printf("%d\n",ans); 48 else printf("-1\n"); 49 } 50 return 0; 51 }
F(法1)
法2:dp[i]代表从0到i时最小的疲惫值.
转移时分为两种情况:
dp[i+1]=min(dp[i+1],dp[i]) (第i+1个点没下雨)
dp[j]=min(dp[j]+dp[i]+(j-i)*x) (第i个点有伞) (i+1<=j<=a,x代表在第i个点的伞的重量) 该转移代表的含义是,拿着这把伞后从i点能到哪个位置(j)
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int maxn=2010; 6 const int inf=1e9; 7 int b[maxn],w[maxn],dp[maxn],mas[maxn]; 8 bool vis[maxn]; 9 10 int main() 11 { 12 int a,n,m,i,j,k,x,y,z,ans,l,r; 13 while ( scanf("%d%d%d",&a,&n,&m)!=EOF ) 14 { 15 memset(vis,false,sizeof(vis)); 16 for ( i=1;i<=n;i++ ) 17 { 18 scanf("%d%d",&l,&r); 19 for ( j=l+1;j<=r;j++ ) vis[j]=true; 20 } 21 for ( i=0;i<=a;i++ ) dp[i]=mas[i]=inf; 22 for ( i=1;i<=m;i++ ) 23 { 24 scanf("%d%d",&b[i],&w[i]); 25 mas[b[i]]=min(mas[b[i]],w[i]); 26 } 27 dp[0]=0; 28 for ( i=0;i<a;i++ ) 29 { 30 if ( dp[i]==inf ) continue; 31 if ( !vis[i+1] ) dp[i+1]=min(dp[i+1],dp[i]); 32 if ( mas[i]!=inf ) 33 { 34 for ( j=i+1;j<=a;j++ ) dp[j]=min(dp[j],dp[i]+(j-i)*mas[i]); 35 } 36 } 37 if ( dp[a]!=inf ) printf("%d\n",dp[a]); 38 else printf("-1\n"); 39 } 40 return 0; 41 }
F(法2)
原文地址:https://www.cnblogs.com/HDUjackyan/p/9125241.html