2020 GDUT Rating Contest I(div2)
A Cow Gymnastics
题意:
给出K组数据(1<=K<=10),每组数据有N头奶牛的排名(1<=N<=20),求这K组数据中奶牛的相对排位是一致的奶牛的对数,对于每组数据a[i]=j意味着在这组数据中 j 号奶牛排名为i。
解题思路:
直接暴力做,用一个n*n的矩阵记录所有的数对(i,j),表示i号奶牛的排名是否一直高于j号奶牛的排名。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
int mp[25][25];
int main(){
int k,n;
memset(mp,1,sizeof(mp));
scanf("%d %d",&k,&n);
for (int i=1;i<=k;i++){
int a[25];
for (int j=1;j<=n;j++){
scanf("%d",&a[j]);
for (int k=1;k<j;k++)
mp[a[j]][a[k]]=0;
}
}
int ans=0;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (i!=j&&mp[i][j]) ans++;
printf("%d\n",ans);
return 0;
}
B MooBuzz
题意:
给出一个整数N(1<=N<=1e9),问数列X∈N且X%3!=0且X%5!=0中第N个数是多少。
解题思路:
可以用容斥原理直接得出答案,但是当时看到题就想用二分答案。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
long long check(long long x){
return x-x/3-x/5+x/15;
}
int main(){
int n;
scanf("%d",&n);
long long l=0,r=1000000000000000000;
while (l+1<r){
long long mid=(l+r)/2;
long long t=check(mid);
if (t>=n) r=mid;
else if (t<n) l=mid;
}
printf("%lld\n",r);
return 0;
}
C Moortal Cowmbat
题意:
给出一个只包含小写字母的长度为N的字符串(1<=N<=1e5)
给出一个M*M的矩阵,表示要使字母变化的花费。
给出一个K,要求变化后的字符串中的每个字母至少连续重复k次。
解题思路:
四边形不等式dp,dp[i][j]表示长度为i的字符串以字母j结尾时的最少花费。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<iostream>
using namespace std;
long long dp[100005][30],f[100005][30];
int g[30][30];
int main(){
int n,m,k;
char s[100005];
scanf("%d %d %d\n%s",&n,&m,&k,s);
for (int i=1;i<=m;i++)
for (int j=1;j<=m;j++)
scanf("%d",&g[i][j]);
for (int k=1;k<=m;k++)
for (int i=1;i<=m;i++)
for (int j=1;j<=m;j++)
g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
for (int j=1;j<=m;j++)
for (int i=1;i<=n;i++)
f[i][j]=f[i-1][j]+g[s[i-1]-'a'+1][j];
for (int i=1;i<=m;i++)
dp[k][i]=f[k][i];
for (int i=k+1;i<=n;i++){
long long mi=0x3f3f3f3f3f3f3f3f;
if (i>=k*2)
{
for (int j=1;j<=m;j++)
mi=min(mi,dp[i-k][j]);
for (int j=1;j<=m;j++)
dp[i][j]=mi+f[i][j]-f[i-k][j];
for (int j=1;j<=m;j++)
dp[i][j]=min(dp[i][j],dp[i-1][j]+g[s[i-1]-'a'+1][j]);
}
else
{
for (int j=1;j<=m;j++)
dp[i][j]=f[i][j];
}
}
long long ans=0x3f3f3f3f3f3f3f3f;
for (int i=1;i<=m;i++)
ans=min(ans,dp[n][i]);
printf("%lld\n",ans);
return 0;
}
D Meetings
题意:
给出N头牛(1<=N<=5e4),给出长为L的小路。
每头牛的体重w[i],起始坐标x[i],速度v[i](只有1或者-1)。
两头牛相遇时两头牛转向继续走,之后有体重总和达到所有牛的体重总和的一半以上的牛到达路的两端时才结束,统计牛相遇的次数。
解题思路:
先假设牛相遇时不会转向,而是直接穿过去(因为这样不影响统计到达终点的牛的数量),那么只要对时间T二分查找即可找到一个时间使得符合条件的牛的数目到达终点,然后再统计相遇次数即可。
直接模拟牛的相遇显然会超时,只需要把往左(右)走的牛的位置记录下来,然后再枚举往右(左)走的牛,判断这头牛前方2*T的距离内有多少只往左(右)走的牛就是相遇次数,累加求和即可得到答案。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
using namespace std;
struct node{
int w,x,v;
}cow[50005];
int a[50005];
int cnt=1,n,len,sum;
bool cmp(node a,node b){
return a.x<b.x;
}
bool check(int t){
int weight=0,l=0,r=0;
for (int i=1;i<=n;i++){
if (cow[i].v==-1&&cow[i].x<=t) l++;
if (cow[i].v==1&&len-cow[i].x<=t) r++;
}
for (int i=1;i<=l;i++) weight+=cow[i].w;
for (int i=n;i>n-r;i--) weight+=cow[i].w;
return weight*2>=sum;
}
int count(int x){
int l=0,r=cnt;
while (r-l>1){
int mid=(l+r)/2;
if (a[mid]<=x) l=mid;
else r=mid;
}
return l;
}
void meet(int t){
int ans=0;
for (int i=1;i<=n;i++)
if (cow[i].v==-1) a[cnt++]=cow[i].x;
for (int i=1;i<=n;i++)
if (cow[i].v==1) ans+=count(cow[i].x+t*2)-count(cow[i].x);
printf("%d\n",ans);
}
int main(){
scanf("%d %d",&n,&len);
for (int i=1;i<=n;i++){
scanf("%d %d %d",&cow[i].w,&cow[i].x,&cow[i].v);
sum+=cow[i].w;
}
sort(cow+1,cow+1+n,cmp);
int l=0,r=len;
while (r-l>1){
int mid=(l+r)/2;
if (check(mid)) r=mid;
else l=mid;
}
meet(r);
return 0;
}
E Milk Visits
题意:
给出一颗有N个节点的树,树的结点有两种状态,有M个询问,问从节点u到节点v的路上是否有某个状态的节点。
解题思路:
在建边时,把状态相同的节点连成同一个连通块,只要路径上经过了两种状态的节点,那么他们就不属于同一个连通块,在查询时只要判断两个点是否属于同一连通块及连通块的状态是否是需要的状态即可知道能不能满足要求。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int f[100005];
char s[100005];
int ans[100005];
int father(int u){
return f[u]==u?u:f[u]=father(f[u]);
}
void merge(int x,int y){
int fx=father(x);
int fy=father(y);
f[fx]=f[fy];
return;
}
int main(){
int n,m;
scanf("%d %d\n%s",&n,&m,s+1);
for (int i=1;i<=n;i++)
f[i]=i;
int u,v;
char c;
for (int i=1;i<n;i++){
scanf("%d %d",&u,&v);
if (s[u]==s[v])merge(u,v);
}
for (int i=1;i<=m;i++){
scanf("%d %d %c",&u,&v,&c);
if (father(f[u])==father(f[v])&&c!=s[u]) ans[i]=0;
else ans[i]=1;
}
for (int i=1;i<=m;i++)
printf("%d",ans[i]);
return 0;
}
G Livestock Lineup
题意:
按题目的要求输出一组符合要求的排列顺序。
解题思路:
直接枚举所有可能性即可,可以用next_permutation,但是那会我还不知道这个库函数,所以写了dfs。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<vector>
#include<map>
using namespace std;
int n,flg;
int a[10],vis[10];
map<string,int> mp1;
map<int,string> mp2;
int b[8][2];
void dfs(int k)
{
if (flg) return;
if(k==9)
{
for(int i=1;i<=n;i++)
{
int x,y;
for(int j=1;j<=8;j++)
if(a[j]==b[i][0]) x=j;
else if(a[j]==b[i][1]) y=j;
if(abs(x-y)!=1) return;
}
for(int i=1;i<=8;i++)
cout<<mp2[a[i]]<<endl;
flg=1;
return;
}
for(int j=1;j<=8;j++)
{
if(vis[j]==0)
{
vis[j]=1;
a[k] = j;
dfs(k+1);
vis[j]=0;
}
}
}
int main()
{
mp1["Beatrice"]=1,mp2[1]="Beatrice";
mp1["Belinda"]=2,mp2[2]="Belinda";
mp1["Bella"]=3,mp2[3]="Bella";
mp1["Bessie"]=4,mp2[4]="Bessie";
mp1["Betsy"]=5,mp2[5]="Betsy";
mp1["Blue"]=6,mp2[6]="Blue";
mp1["Buttercup"]=7,mp2[7]="Buttercup";
mp1["Sue"]=8,mp2[8]="Sue";
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
string s;
cin>>s;
b[i][0]=mp1[s];
cin>>s;cin>>s;cin>>s;cin>>s;
cin>>s;
b[i][1]=mp1[s];
}
dfs(1);
return 0;
}