A - Angle Beats
根据点成a点b=|a||b|cosx。当x=90度或者x=270度时,点乘等于0。于是有
x1x2+y1y2=0->x1x2=-y1y2->x1/y1=-y2/x1。于是我们分两种情况,点U是直角点,不是直角点,把x1/y1压入map,但是我们不能压浮点数,要压最简分数形式,所以还要求一次GCD,时间复杂度O(N^2*log2(n)),因为要求gcd,所以用map会炸,我们要用unordered_map。
#include<bits/stdc++.h>
#include<assert.h>
using namespace std;
typedef long long ll;
const int N=2005;
int n,q,sx,sy,x[N],y[N];
ll mul=4e9;
unordered_map<ll,int>vis[N],mp;
void cal(int &x,int &y)
{
int k=__gcd(x,y);x/=k;y/=k;
if(x<0) x*=-1,y*=-1;
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
scanf("%d%d",&x[i],&y[i]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
int xx=x[j]-x[i],yy=y[j]-y[i];
if(xx==0&&yy==0) continue;
cal(xx,yy);
vis[i][xx*mul+yy+2e9]++;
}
while(q--)
{
scanf("%d%d",&sx,&sy);
int ans=0;
for(int i=1;i<=n;i++)
{
int xx=sx-x[i],yy=sy-y[i];
if(xx==0&&yy==0) continue;
swap(xx,yy);xx*=-1;
cal(xx,yy);
ans+=vis[i][xx*mul+yy+2e9];
}
mp.clear();
int res=0;
for(int i=1;i<=n;i++)
{
int xx=x[i]-sx,yy=y[i]-sy;
if(xx==0&&yy==0) continue;
swap(xx,yy);xx*=-1;
cal(xx,yy);
ans+=mp[xx*mul+yy+2e9];
swap(xx,yy);xx*=-1;
cal(xx,yy);
mp[xx*mul+yy+2e9]++;
}
printf("%d\n",ans);
}
}
D - Decimal
水题
#include<bits/stdc++.h>
using namespace std;
int n,t;
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
while(n%2==0) n/=2;
while(n%5==0) n/=5;
if(n!=1) printf("Yes\n");
else printf("No\n");
}
}
F - Forest Program Gym
注意一条边只在一个环里,考虑在每条边选和不选,一共有2^m个状态,但是在一个环里的边我们不能全选,所以一个长度为x的环里的贡献是2的x次方减1。所以把环里的答案和环外的连乘即可。统计一个环里的边数,可以用tarjan,但是我比较懒,我就直接用LCT做了,因为环里的点数就是边数,所以在LCT时同理点u和点v的路径间点的个数即可。
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5,mod=998244353;
typedef long long ll;
ll ans=1,p[N];
int n,m,sum,root,a[N],t[N][2],fa[N],lz[N],s[N];
void pushup(int x)
{
s[x]=s[t[x][0]]+s[t[x][1]]+1;
}
void update(int x){
swap(t[x][0],t[x][1]);lz[x]^=1;}
void pushdown(int x)
{
if(lz[x])
{
if(t[x][0]) update(t[x][0]);
if(t[x][1]) update(t[x][1]);
lz[x]=0;
}
}
bool nroot(int x)
{
return t[fa[x]][0]==x|t[fa[x]][1]==x;
}
void Rotate(int x)
{
int y=fa[x],z=fa[y],k=(t[y][1]==x)^1;
if(nroot(y)) t[z][t[z][1]==y]=x;
t[y][k^1]=t[x][k];
if(t[x][k]) fa[t[x][k]]=y;
t[x][k]=y;
fa[y]=x;
fa[x]=z;
pushup(y);
}
int st[N];
void splay(int x)
{
int y=x,z=0;
st[++z]=y;
while(nroot(y)) st[++z]=y=fa[y];
while(z) pushdown(st[z--]);
while(nroot(x))
{
y=fa[x],z=fa[y];
if(nroot(y)) Rotate((t[y][1]==x)^(t[z][1]==y)?x:y);
Rotate(x);
}
pushup(x);
}
void access(int x)
{
for(int y=0;x;x=fa[y=x])
{
splay(x);t[x][1]=y;pushup(x);
}
}
void makeroot(int x)
{
access(x);splay(x);update(x);
}
int findroot(int x)
{
access(x);splay(x);
while(t[x][0]) pushdown(x),x=t[x][0];
splay(x);
return x;
}
void link(int x,int y)
{
makeroot(x);
fa[x]=y;
}
void cut(int x,int y)
{
makeroot(x);
if(findroot(y)==x&&fa[y]==x&&!t[y][0])
{
fa[y]=t[x][1]=0;
pushup(x);
}
}
void split(int x,int y)
{
makeroot(x);
access(y);splay(y);
}
bool connect(int u,int v)
{
makeroot(u);
return findroot(v)==u;
}
void add(int u,int v)
{
if(connect(u,v))
{
split(u,v);
ans=ans*(p[s[v]]-1)%mod;
sum-=s[v];
}
else link(u,v);
}
int main()
{
p[0]=1;
for(int i=1;i<N;i++) p[i]=p[i-1]*2%mod;
scanf("%d%d",&n,&m);sum=m;
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
}
ans=ans*p[sum]%mod;
printf("%lld\n",ans);
}
I - Invoker
这个不是暴力dp吗,设dp[l][i][j][k]表示放了第l个技能,最后放的技能时k,倒数第二次放的技能时j,倒数第三次放的技能时i,按的最少的次数。然后随便转移即可。
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const int N=1e5+5;
bool f[26][3][3][3];
int dp[N][3][3][3];
void init()
{
f['Y'-'A'][0][0][0]=true;
f['V'-'A'][0][0][2]=true;
f['V'-'A'][2][0][0]=true;
f['V'-'A'][0][2][0]=true;
f['G'-'A'][0][0][1]=true;
f['G'-'A'][0][1][0]=true;
f['G'-'A'][1][0][0]=true;
f['C'-'A'][2][2][2]=true;
f['X'-'A'][0][2][2]=true;
f['X'-'A'][2][0][2]=true;
f['X'-'A'][2][2][0]=true;
f['Z'-'A'][2][2][1]=true;
f['Z'-'A'][1][2][2]=true;
f['Z'-'A'][2][1][2]=true;
f['T'-'A'][1][1][1]=true;
f['F'-'A'][0][1][1]=true;
f['F'-'A'][1][0][1]=true;
f['F'-'A'][1][1][0]=true;
f['D'-'A'][2][1][1]=true;
f['D'-'A'][1][2][1]=true;
f['D'-'A'][1][1][2]=true;
f['B'-'A'][0][1][2]=true;
f['B'-'A'][0][2][1]=true;
f['B'-'A'][1][2][0]=true;
f['B'-'A'][1][0][2]=true;
f['B'-'A'][2][0][1]=true;
f['B'-'A'][2][1][0]=true;
}
char s[N];
int main()
{
init();
scanf("%s",s+1);
int n=strlen(s+1);
memset(dp,inf,sizeof(dp));
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
for(int k=0;k<3;k++)
dp[0][i][j][k]=3;
for(int l=1;l<=n;l++)
{
int p=s[l]-'A',mn=inf;
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
for(int k=0;k<3;k++)
{
if(f[p][i][j][k])
dp[l][i][j][k]=min(dp[l][i][j][k],dp[l-1][i][j][k]+1);
mn=min(mn,dp[l-1][i][j][k]);
}
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
for(int k=0;k<3;k++)
if(f[p][i][j][k])
{
dp[l][i][j][k]=min(dp[l][i][j][k],mn+4);
}
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
for(int k=0;k<3;k++)
if(f[p][i][j][k])
{
dp[l][i][j][k]=min(dp[l][i][j][k],dp[l-1][i][j][k]+1);
dp[l][i][j][k]=min(dp[l][i][j][k],dp[l-1][0][i][j]+2);
dp[l][i][j][k]=min(dp[l][i][j][k],dp[l-1][1][i][j]+2);
dp[l][i][j][k]=min(dp[l][i][j][k],dp[l-1][2][i][j]+2);
dp[l][i][j][k]=min(dp[l][i][j][k],dp[l-1][0][0][i]+3);
dp[l][i][j][k]=min(dp[l][i][j][k],dp[l-1][0][1][i]+3);
dp[l][i][j][k]=min(dp[l][i][j][k],dp[l-1][0][2][i]+3);
dp[l][i][j][k]=min(dp[l][i][j][k],dp[l-1][1][0][i]+3);
dp[l][i][j][k]=min(dp[l][i][j][k],dp[l-1][1][1][i]+3);
dp[l][i][j][k]=min(dp[l][i][j][k],dp[l-1][1][2][i]+3);
dp[l][i][j][k]=min(dp[l][i][j][k],dp[l-1][2][0][i]+3);
dp[l][i][j][k]=min(dp[l][i][j][k],dp[l-1][2][1][i]+3);
dp[l][i][j][k]=min(dp[l][i][j][k],dp[l-1][2][2][i]+3);
}
}
int ans=inf;
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
for(int k=0;k<3;k++)
ans=min(ans,dp[n][i][j][k]);
printf("%d\n",ans);
}
J - MUV LUV EXTRA
赤裸裸的kmp。可以发现A乘的就时从在第i个字符后面的字符数量,所以我们只需要最小化循环节的长度len即可,这符合kmp的性质。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e7+5;
ll a,b;
int n,nex[N];
char s[N];
void kmp_init()
{
int i=1,k=0;
while(i<=n)
if(k==0||s[i]==s[k]) nex[++i]=++k;
else k=nex[k];
}
int main()
{
scanf("%lld%lld",&a,&b);
scanf("%s",s+1);
n=strlen(s+1);
reverse(s+1,s+1+n);
while(s[n]!='.'&&n) n--;
if(n==0)
{
printf("%d\n",0);return 0;
}
n--;
s[n+1]='\0';
kmp_init();
ll ans=-1e18;
for(int i=1;i<=n;i++)
{
int p=nex[i+1]-1;
int len=i-p;
ans=max(ans,i*a-b*len);
}
printf("%lld\n",ans);
}