round 607
A
题意
根据后缀判断出自哪种语言
思路
水题
代码
#include<bits/stdc++.h>
using namespace std;
const int MAX=1e3+3;
char s[MAX];
int main()
{
int T;
cin>>T;
while(T--)
{
scanf("%s",s);
int len=strlen(s);
if(s[len-2]=='p'&&s[len-1]=='o')
{
printf("FILIPINO
");
continue;
}
if(s[len-4]=='d'&&s[len-3]=='e'&&s[len-2]=='s'&&s[len-1]=='u')
{
printf("JAPANESE
");
continue;
}
if(s[len-4]=='m'&&s[len-3]=='a'&&s[len-2]=='s'&&s[len-1]=='u')
{
printf("JAPANESE
");
continue;
}
if(s[len-5]=='m'&&s[len-4]=='n'&&s[len-3]=='i'&&s[len-2]=='d'&&s[len-1]=='a')
{
printf("KOREAN
");
continue;
}
}
}
B
题意
给两个字符串a,b,a可以交换任意一对字符(只能交换一次),问能否使得a字典序小于b
思路
贪心,越小的字符越前则越好,处理一下后缀min,然后从前往后判断能否交换就好了。这样一定是最优的,交换完了以后比较一下输出结果。
代码
#include<bits/stdc++.h>
using namespace std;
const int MAX=5e3+3;
char s[MAX],c[MAX],minn[MAX];
int index[MAX];
int main()
{
int T;
cin>>T;
while(T--)
{
scanf("%s%s",s,c);
int lens=strlen(s);
minn[lens-1]=s[lens-1];
index[lens-1]=lens-1;
for(int i=lens-2; i>0; i--)
{
index[i]=index[i+1];
minn[i]=minn[i+1];
if(s[i]<minn[i+1])
{
index[i]=i;
minn[i]=s[i];
}
}
for(int i=0; i<lens-1; i++)
if(s[i]>minn[i+1])
{
swap(s[i],s[index[i+1]]);
break;
}
if(strcmp(s,c)<0)
printf("%s
",s);
else
printf("---
");
}
}
C
题意
给一个字符串,由1,2,3组成。然后模拟一个光标,每次操作光标向右移动一位,然后把光标左右字符串切开成sl和sr,然后把sr在sl后粘贴【sl的最后一位】次。问操作x次之后此字符串的长度,输出对1e9+7取模。
思路
看起来好像是找规律,但是实际上暴力模拟就行了。因为每次操作只向右移动一位,所以总共需要记录的字符不超过x个。所以模拟复杂度O(x)。
代码
#include<bits/stdc++.h>
using namespace std;
const int MAX=2e6+6;
const int mod=1e9+7;
char s[MAX];
int main()
{
int T;
cin>>T;
while(T--)
{
int x;
scanf("%d%s",&x,s+1);
int len=strlen(s+1);
int res=len;
for(int i=1; i<=x; i++)
{
if(s[i]=='1')continue;
int cnt=s[i]-'1';
int cur=(res-i+mod)%mod;
if(len<x)
{
len+=cur;
for(int j=1;j<=cnt;j++)
for(int k=i+1; k<=len&&k+j*cur<=x; k++)
s[k+j*cur]=s[k];
}
res=((res+cur*cnt*1ll)%mod+mod)%mod;
}
printf("%d
",(res+mod)%mod);
}
}
D
题意
给一个字符矩阵,由A,P构成。每次操作可以选1×K的一段或K×1的一段,然后向上下或左右扩展任意长度,使得扩展的那段也变成和选择的那段一样,求最少多少次可以把整个矩阵全变成A。
思路
显然,若答案存在,则在 [0,4] 之间。然后先按行再按列判断一下就好了,先判是不是整行/列,然后判是不是在边上…………,计算答案取 min 即可。
代码
#include<bits/stdc++.h>
using namespace std;
const int MAX=66;
char G[MAX][MAX];
int main()
{
int T;
cin>>T;
while(T--)
{
int n,m,res=MAX,cnt=0;
scanf("%d%d",&n,&m);
for(int i=0; i<n; i++)
scanf("%s",G[i]);
for(int i=0; i<n; i++)
{
bool flag1=1,flag2=0;
for(int j=0; j<m; j++)
{
flag1&=(G[i][j]=='A');
flag2|=(G[i][j]=='A');
cnt+=(G[i][j]=='A');
}
if(flag1)
{
if(i==0||i==n-1)
res=min(res,1);
else
res=min(res,2);
}
else
{
if(!flag2)continue;
if(G[i][0]=='A'||G[i][m-1]=='A')
{
if(i==0||i==n-1)
res=min(res,2);
else
res=min(res,3);
}
else
{
if(i==0||i==n-1)
res=min(res,3);
else
res=min(res,4);
}
}
}
if(cnt==n*m)
{
printf("0
");
continue;
}
for(int j=0; j<m; j++)
{
bool flag1=1,flag2=0;
for(int i=0; i<n; i++)
{
flag1&=(G[i][j]=='A');
flag2|=(G[i][j]=='A');
}
if(flag1)
{
if(j==0||j==m-1)
res=min(res,1);
else
res=min(res,2);
}
else
{
if(!flag2)continue;
if(G[0][j]=='A'||G[n-1][j]=='A')
{
if(j==0||j==m-1)
res=min(res,2);
else
res=min(res,3);
}
else
{
if(j==0||j==m-1)
res=min(res,3);
else
res=min(res,4);
}
}
}
if(res==MAX)
printf("MORTAL
");
else
printf("%d
",res);
}
}
E
题意
给一棵带权树,2k个节点,将k对人分配到此树的节点上,求分配后每一对人两者距离之和的最大值和最小值。
思路
可以想到最大值就要每一对的两个人尽量远,最小值就是两个人尽量近。所以先求出树的重心,记为rt。则可以认为rt将树分为左右两部分(不一定是两子树),两者节点数相差1。在此模型上考虑。
最大值就是左边的全部与右边的配对,不与自己部分的配对,可以发现最大值就是所有节点到rt的距离之和。
最小值就是每一部分尽量自给自足。则可以想到:从rt出发开始遍历,如果子树的节点个数为偶数,那么自给自足一定优于连边到rt,所以连到此子树的边权一定没有贡献。如果子树的节点数为奇数,那么一定无法自给自足,那么此子树一定要连到rt上。然后问题可以分解成子问题。每个子问题求一个节点x的所有子树的贡献。边界为叶子节点,叶子节点一定要连到父亲节点上,也符合奇偶规律。
代码
#include<bits/stdc++.h>
using namespace std;
const int MAX=2e5+5;
typedef long long ll;
struct Edge
{
int to,val,nxt;
}edges[MAX<<1];
int head[MAX],siz[MAX],mx_son_siz[MAX],n,tot,rt;
ll minn,maxx;
inline void addedge(int u,int v,int w)
{
edges[tot].to=v;
edges[tot].val=w;
edges[tot].nxt=head[u];
head[u]=tot++;
}
void getroot(int x,int fa)
{
siz[x]=1;
mx_son_siz[x]=0;
for(int i=head[x];i!=-1;i=edges[i].nxt)
{
int v=edges[i].to;
if(v==fa)continue;
getroot(v,x);
siz[x]+=siz[v];
mx_son_siz[x]=max(mx_son_siz[x],siz[v]);
}
mx_son_siz[x]=max(mx_son_siz[x],n-siz[x]);
if(!rt||mx_son_siz[x]<mx_son_siz[rt])
rt=x;
}
void dfs(int x,int fa,ll sum,int w)
{
siz[x]=1;
for(int i=head[x];i!=-1;i=edges[i].nxt)
{
int v=edges[i].to;
if(v==fa)continue;
dfs(v,x,sum+edges[i].val,edges[i].val);
siz[x]+=siz[v];
}
if(siz[x]&1)
minn+=w;
maxx+=sum;
}
void init()
{
for(int i=1;i<=n;i++)
head[i]=-1;
rt=tot=0;
minn=maxx=0ll;
}
int main()
{
int T;
cin>>T;
while(T--)
{
scanf("%d",&n);
n<<=1;
init();
for(int i=1;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
addedge(u,v,w);
addedge(v,u,w);
}
getroot(1,-1);
dfs(rt,-1,0,0);
printf("%I64d %I64d
",minn,maxx);
}
}