A - Angry Students
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int t,n,mx,last;
char st[205];
int main(){
cin>>t;
while(t--)
{
last=mx=0;
cin>>n;
getchar();
for(int i=1;i<=n;i++)
st[i]=getchar();
for(int i=1;i<=n;i++)
{
if(st[i]=='A')
{
if(last)
mx=max(mx,i-last-1);
last=i;
}
}
if(last) mx=max(mx,n-last);
cout<<mx<<endl;
}
}
B - Fadi and LCM
- 给定小于1e12的正整数x,求a,b使得a,b的最小公倍数是x且max(a,b)最小。
- a和b一定是x两部分质因子的乘积,也就是说a,b是x的因子,从1枚举到sqrt(x)即可。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
long long x;
long long gcd(long long a,long long b)
{
return b?gcd(b,a%b):a;
}
int main(){
cin>>x;
for(long long i=sqrt(x);i>=1;i--)
if(!(x%i)&&gcd(i,x/i)==1)
{
cout<<min(x/i,i)<<' '<<max(x/i,i);
return 0;
}
cout<<1<<' '<<x;
return 0;
}
C - Cut and Paste
- 给定由1 2 3组成的字符串,进行n此操作,第i此操作将第i+1个字符到最后一个字符复制第i个字符代表的数字-1次粘贴到字符串后面,求最后的字符串长度,答案对1e9+7取模。
- 模拟操作直到当前字符串长度大于等于n,后面的每次直接计算长度,每次计算在过程中取模,注意如果取模后的长度可能小于本次未复制部分的长度,每次需要先加1e9+7再取模。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
const long long mod=1e9+7;
int n,t,tim;
long long len;
char s[10000005],c;
int main()
{
cin>>t;
while(t--)
{
tim=len=0;
scanf("%d\n",&n);
while(c=getchar())
{
if(c!='\n')
s[++len]=c;
else
break;
}
for(int i=1;i<=n;i++)
{
int last=len;
for(int j=1;j<=s[i]-'0'-1;j++)
{
for(int k=i+1;k<=last;k++)
s[++len]=s[k];
}
tim=i;
if(len>=n)
break;
}
for(long long i=tim+1;i<=n;i++)
{
long long last=len;
len=((long long)(len+mod-i)%mod*(long long)(s[i]-'0')%mod+i)%mod;
}
cout<<(long long)len<<endl;
}
}
D - Numbers on Tree
- 给出一棵有根树,对于每个点给出该点的子树有多少个点的权值比该点小,输出这棵树各个点的权值。
- n很小,可以乱做。对于每个点,题中信息相当于给了该点在该子树下权值的排名,维护每棵子树的排名(按权值从小到大),对于每个点将其各个儿子下的排名序列排在一起,然后将自己插入,如果自己的排名比这个序列长,则无解。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
int n,a[2005],last[2006],cnt,lef[2005],rig[2005],root,fa[2005];
bool ans;
struct edge{
int v,next;
}e[10005];
inline void add(int u,int v)
{
e[++cnt].v=v;
e[cnt].next=last[u];
last[u]=cnt;
}
vector<int>vec[2005];
void dfs(int u,int f)
{
for(int i=last[u];i;i=e[i].next)
{
int v=e[i].v;
if(v==f) continue;
dfs(v,u);
vec[u].insert(vec[u].end(),vec[v].begin(),vec[v].end());
}
if(a[u]>vec[u].size())
{
ans=1;
return ;
}
vec[u].insert(vec[u].begin()+a[u],u);
}
int main(){
cin>>n;
for(int i=1,u;i<=n;i++)
{
scanf("%d%d",&u,&a[i]);
fa[i]=u;
if(u){
add(u,i);
add(i,u);
}
else
root=i;
}
dfs(root,0);
if(!ans)
{
int tmp=1;
cout<<"YES"<<endl;
for(int i=0;i<vec[root].size();i++)
a[vec[root][i]]=tmp+i;
cout<<a[1];
for(int i=2;i<=n;i++)
cout<<' '<<a[i];
}
else
cout<<"NO";
return 0;
}
E - Beautiful Rectangle
- 给出一个序列,要求用到尽可能多的元素组成一个矩阵,使得矩阵的每一行每一列没有相同元素。
- 1~sqrt(n)枚举矩阵的一条边,此情况下出现次数为cnt的元素可在矩阵中被使用min(cnt,当前枚举的长度)次,求出当前矩阵的大小,保留最大的和矩阵形状。最后将元素往里面填,以斜对角线的顺序填,先填使用最多的元素。网上的这个在一维里面存矩阵的方法代码比较好写。
#include <iostream>
#include <cstdio>
#include <map>
#include <algorithm>
#include <cmath>
using namespace std;
int n,a[400005],last=1,mx,m,mxl,mxr,ans[400005];
map<int,int>inq;
struct ele
{
int x,num;
} e[400004];
bool cmp(const ele &a,const ele &b)
{
if(a.num==b.num)
return a.x<b.x;
return a.num>b.num;
}
int main()
{
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
inq[a[i]]++;
}
for(int i=1; i<=n; i++)
{
if(inq[a[i]])
e[++m]= {a[i],inq[a[i]]};
inq[a[i]]=0;
}
sort(e+1,e+1+m,cmp);
for(int i=sqrt(n); i>=1; i--)
{
int ans=0;
for(int j=1; j<=m; j++)
ans+=min(e[j].num,i);
if(ans-ans%i<i*i) continue;
if(ans-ans%i>mx)
{
mx=ans-ans%i;
mxl=i;
mxr=ans/i;
}
}
for(int i=1; i<=m; i++)
e[i].num=min(e[i].num,min(mxl,mxr));
cout<<mx<<endl<<mxl<<' '<<mxr<<endl;
int p=1;
for(int i=1; i<=mxr; i++)
{
for(int j=1; j<=mxl; j++)
{
if(e[p].num==0) p++;
ans[(j-1)*mxr+(i+j)%mxr+1] = e[p].x;
e[p].num--;
}
}
for(int i=1; i<=mx; i++)
{
cout << ans[i] << " ";
if(i%mxr==0) cout << endl;
}
return 0;
}