Codeforces Round #445 Div. 1

时间:2024-01-18 18:18:44

  A:每次看是否有能走回去的房间,显然最多只会存在一个,如果有走过去即可,否则开辟新房间并记录访问时间。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 200010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
int n,a[N],id[N],ans;
signed main()
{
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
n=read();
for (int i=1;i<=n;i++) a[i]=read();
int cur=ans=1;id[0]=1;
for (int i=1;i<=n;i++)
{
if (id[a[i]]) cur=id[a[i]],id[a[i]]=0;
else cur=++ans;
id[i]=cur;
}
cout<<ans;
return 0;
//NOTICE LONG LONG!!!!!
}

  B:注意到单个字母一定是出现次数最多的子串之一。所以如果给定字符串中有字符重复出现,一定无解。并且可以得到答案字符串中也一定没有字符重复出现,其长度<=26。于是怎么暴力都行了。考虑将所有串按长度从大到小排序,动态维护当前答案,答案由一个字符串数组构成。每次加入一个字符串时,先看是否被答案中某字符串包含,否则再看其是否能拼接两个字符串,若不能继续看能否和某个字符串拼接,都不行的话将其加入字符串数组。最后将数组排序即可。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 100010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
int n,cnt[26];
string a[N],ans[100];
bool cmp(const string&a,const string&b)
{
return a.length()>b.length();
}
void check(string a)
{
memset(cnt,0,sizeof(cnt));
for (int j=0;j<a.length();j++)
{
if (cnt[a[j]-'a']) {cout<<"NO";exit(0);}
cnt[a[j]-'a']++;
}
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
n=read();
for (int i=1;i<=n;i++)
{
cin>>a[i];check(a[i]);
}
sort(a+1,a+n+1,cmp);ans[1]=a[1];
int u=1;
for (int i=2;i<=n;i++)
{
bool flag=0;
for (int x=1;x<=u;x++)
{
for (int y=1;y<=u;y++)
if (x!=y)
{
for (int k=1;k<a[i].size();k++)
if (ans[x].substr(ans[x].size()-k,k)+ans[y].substr(0,a[i].size()-k)==a[i])
{
flag=1;
ans[x]=ans[x].substr(0,ans[x].size()-k)+a[i]+ans[y].substr(a[i].size()-k,ans[y].size()-(a[i].size()-k));
ans[y].clear();
check(ans[x]);break;
}
if (flag) break;
}
if (flag) break;
}
if (flag)
{
for (int k=1;k<=u;k++)
if (ans[k].size()==0)
{
for (int p=k;p<u;p++) ans[p]=ans[p+1];
u--;break;
}
continue;
}
for (int k=1;k<=u;k++)
{
for (int j=0;j<ans[k].size()-a[i].size()+1;j++)
if (ans[k].substr(j,a[i].size())==a[i]) {flag=1;break;}
if (flag) {check(ans[k]);break;}
for (int j=ans[k].size()-a[i].size()+1;j<ans[k].size();j++)
if (ans[k].substr(j,ans[k].size()-j)==a[i].substr(0,ans[k].size()-j))
{
ans[k]=ans[k].substr(0,j)+a[i];flag=1;break;
}
if (flag) {check(ans[k]);break;}
for (int j=1;j<a[i].size();j++)
if (a[i].substr(j,a[i].size()-j)==ans[k].substr(0,a[i].size()-j))
{
ans[k]=a[i].substr(0,j)+ans[k];flag=1;break;
}
if (flag) {check(ans[k]);break;}
}
if (!flag)
{
ans[++u]=a[i];
for (int k=1;k<u;k++) check(ans[k]+a[i]);
}
}
sort(ans+1,ans+u+1);
for (int i=1;i<=u;i++) cout<<ans[i];
return 0;
//NOTICE LONG LONG!!!!!
}

  C:容易想到一个二维dp,即f[i][j]第i位为j且在前缀单调栈中的方案数。考虑改成一维,固定最后一位为最大值。然后考虑次大值所在位置,分为与最大值距离超过k和不超过k两种情况。若超过k,剩下的数可以任意摆放;若不超过k,变成了一个固定最后一位为次大值的相同子问题,而次大值与最大值之间的数同样可以任意摆放。前缀和优化即可。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 1000010
#define P 1000000007
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
int n,m,fac[N],inv[N],f[N],s[N],ans;
int A(int n,int m){if (m>n) return 0;return 1ll*fac[n]*inv[n-m]%P;}
void inc(int &x,int y){x+=y;if (x>=P) x-=P;}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
#endif
n=read(),m=read();
fac[0]=1;for (int i=1;i<=n;i++) fac[i]=1ll*fac[i-1]*i%P;
inv[0]=inv[1]=1;for (int i=2;i<=n;i++) inv[i]=P-1ll*(P/i)*inv[P%i]%P;
for (int i=2;i<=n;i++) inv[i]=1ll*inv[i]*inv[i-1]%P;
for (int i=m+1;i<=n;i++)
{
f[i]=((i-m-1ll+s[i-1]-s[i-m-1])*fac[i-2]%P+P)%P;
s[i]=(s[i-1]+1ll*f[i]*inv[i-1])%P;
}
for (int i=1;i<=n;i++) inc(ans,1ll*f[i]*A(n-1,n-i)%P);
cout<<ans;
return 0;
//NOTICE LONG LONG!!!!!
}

  D:注意到所有点的质心在直线上的投影就是所有点在直线上的投影的质心。于是关于质心对称的两点始终不会对是否满足中心对称产生影响,将其删去。而对于剩下的点,考虑固定某个点,若其和剩下某个点要中心对称,只有一条直线能满足条件,即与两点质心和所有点质心的连线垂直的过原点的直线。枚举所有直线暴力判断即可。注意去掉相同的直线。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 2010
#define vector point
#define double long double
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
const double eps=1E-11;
const double PI=3.1415926535897932;
int n,ans;
double b[N];
bool flag[N];
struct point{
double x,y;
vector operator +(const vector&a) const
{
return (vector){x+a.x,y+a.y};
}
vector operator -(const vector&a) const
{
return (vector){x-a.x,y-a.y};
}
vector operator *(const double&a) const
{
return (vector){a*x,a*y};
}
double operator *(const vector&a) const
{
return x*a.y-y*a.x;
}
double operator ^(const vector&a) const
{
return x*a.x+y*a.y;
}
double len(){return sqrt(x*x+y*y);}
bool iszero(){return len()<eps;}
vector rotate(double alpha){return (vector){x*cos(alpha)+y*sin(alpha),x*sin(alpha)-y*cos(alpha)};}
}a[N],c[N],P;
signed main()
{
#ifndef ONLINE_JUDGE
freopen("d.in","r",stdin);
freopen("d.out","w",stdout);
#endif
n=read();
for (int i=1;i<=n;i++) a[i].x=read(),a[i].y=read(),P=P+a[i];
P=P*(1.0/n);int cnt=0,t=0;
for (int i=1;i<=n;i++)
for (int j=1;j<=i;j++)
if ((a[i]+a[j]-P*2).iszero()) {flag[i]=flag[j]=1;break;}
for (int i=1;i<=n;i++) if (!flag[i]) a[++t]=a[i];
n=t;t=0;if (!n) {cout<<-1;return 0;}
for (int i=1;i<=n;i++)
{
vector Q=(a[i]+a[1])*0.5-P;
double w=Q.len();
if (fabs(w)<eps) {cnt++;continue;}
w=1.0/w;Q=Q*w;
for (int j=1;j<=n;j++) b[j]=a[j]*Q;
sort(b+1,b+n+1);
bool flag=0;double mid=P*Q;
for (int j=1;j<=n;j++) if (fabs(b[j]+b[n-j+1]-mid*2)>eps) {flag=1;break;}
if (!flag) c[++t]=Q;
}
memset(flag,0,sizeof(flag));
for (int i=1;i<=t;i++)
{
flag[i]=1;
for (int j=1;j<i;j++)
if (flag[j]&&fabs(c[i]*c[j])<eps) {flag[i]=0;break;}
if (flag[i]) ans++;
}
cout<<ans;
return 0;
//NOTICE LONG LONG!!!!!
}

  E看了一年题解都没懂。