A - Wanna go back home
如果S出现过则N必须出现过,如果S没出现过则N必须没出现过。
如果E出现过则W必须出现过,如果E没出现过则W必须没出现过。
#include<bits/stdc++.h>
using namespace std;
#define RI register int
char S[1005];int len,n,s,e,w;
int main()
{
scanf("%s",S+1);
len=strlen(S+1);
for(RI i=1;i<=len;++i)
if(S[i]=='S') s=1;
else if(S[i]=='E') e=1;
else if(S[i]=='W') w=1;
else n=1;
if((s^n)||(e^w)) puts("No");
else puts("Yes");
return 0;
}
B - Simplified mahjong
排序后两两一组,不过可以说是桶排。
#include<bits/stdc++.h>
using namespace std;
#define RI register int
int read() {
int q=0;char ch=' ';
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') q=q*10+ch-'0',ch=getchar();
return q;
}
typedef long long LL;
const int N=100005;
int n,a[N];LL ans;
int main()
{
n=read();
for(RI i=1;i<=n;++i) {
a[i]=read();
if(a[i-1]&&a[i]) --a[i-1],--a[i],++ans;
ans+=(LL)a[i]/2,a[i]&=1;
}
printf("%lld\n",ans);
return 0;
}
C - BBuBBBlesort!
结论:如果 位置的元素距离其目标位置 的距离是奇数,则必须用一次1操作。设这样的元素个数是 个,答案就是
证明:
必要性:2操作不能改变一个元素离它的目标位置的奇偶性。
充分性:两个距离其目标位置是奇数的元素,用2操作一定可以把它们挪到一起,它们两个交换一下位置,一定可以用2操作移回自己的目标位置。
#include<bits/stdc++.h>
using namespace std;
#define RI register int
int read() {
int q=0;char ch=' ';
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') q=q*10+ch-'0',ch=getchar();
return q;
}
typedef long long LL;
const int N=100005;
int n,ans,a[N],b[N];
int main()
{
n=read();
for(RI i=1;i<=n;++i) a[i]=b[i]=read();
sort(b+1,b+1+n);
for(RI i=1;i<=n;++i) {
a[i]=lower_bound(b+1,b+1+n,a[i])-b;
if(abs(i-a[i])&1) ++ans;
}
printf("%d\n",ans/2);
return 0;
}
D - Anticube
将所有数分解质因数,然后将每个质因子的次数都模3,乘回去,这样每个数就有唯一一个对应的不能选的数。如果它和它唯一对应不能选的数是同一个数,就选一个,否则就选数量更大的那一种数。
至于分解质因数,如果你强可以用泼辣的肉,其实只要分解到 以内的质因数即可,剩下的数要么就是 要么就是 ,直接用 开方即可。
#include<bits/stdc++.h>
using namespace std;
#define RI register int
typedef long long LL;
LL read() {
LL q=0;char ch=' ';
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') q=q*10+(LL)(ch-'0'),ch=getchar();
return q;
}
const int N=100000;
int is[N+5];LL a[N+5],b[N+5],pri[N+5];
int n,tot,ans;map<LL,int> mp;
void prework() {
for(RI i=2;i<=N;++i) {
if(!is[i]) pri[++tot]=i;
for(RI j=1;j<=tot&&pri[j]*i<=N;++j) {
is[pri[j]*i]=1;
if(i%pri[j]==0) break;
}
}
}
void work(int o,LL x) {
a[o]=b[o]=1;
for(RI i=1;pri[i]*pri[i]*pri[i]<=x;++i) {
int js=0;
while(x%pri[i]==0) ++js,x/=pri[i];
if(js%3==1) a[o]*=pri[i],b[o]*=pri[i]*pri[i];
else if(js%3==2) a[o]*=pri[i]*pri[i],b[o]*=pri[i];
}
if(x!=1) {
LL kl=sqrt(x);
if(kl*kl==x) a[o]*=kl*kl,b[o]*=kl;
else a[o]*=x,b[o]*=x*x;
}
}
int main()
{
n=read();
prework();
for(RI i=1;i<=n;++i) work(i,read());
for(RI i=1;i<=n;++i) ++mp[a[i]];
for(RI i=1;i<=n;++i) {
if(!mp[a[i]]) continue;
if(a[i]==b[i]) ++ans,mp[a[i]]=0;
else ans+=max(mp[a[i]],mp[b[i]]),mp[a[i]]=mp[b[i]]=0;
}
printf("%d\n",ans);
return 0;
}
E - Sequential operations on Sequence
啊,省队集训做过这题。
首先对于操作序列里的两个数, 且 ,那么 就是无效的了,所以用单调栈把这些操作弄好。
每次二分查找到比你要操作出来的序列刚好小一点的一个操作的编号,将当前序列看做是若干个那个操作的贡献和一个余数的贡献,余数递归求,最多递归 级别次,每个操作统一求(具体看代码吧QAQ…),利用差分区间更新。
#include<bits/stdc++.h>
using namespace std;
#define RI register int
typedef long long LL;
LL read() {
LL q=0;char ch=' ';
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') q=q*10+(LL)(ch-'0'),ch=getchar();
return q;
}
const int N=100005;
int n,Q,top;
LL st[N],num[N],ans[N];
void work(LL len,LL s) {
int k=lower_bound(st+1,st+1+top,len)-st-1;
if(!k) {ans[1]+=s,ans[len+1]-=s;return;}
num[k]+=s*(len/st[k]),work(len%st[k],s);
}
int main()
{
LL x;
n=read(),Q=read(),st[++top]=n;
while(Q--) {
x=read();
while(top&&st[top]>x) --top;
st[++top]=x;
}
num[top]=1;
for(RI i=top;i>=1;--i) work(st[i],num[i]);
for(RI i=1;i<=n;++i) ans[i]+=ans[i-1];
for(RI i=1;i<=n;++i) printf("%lld\n",ans[i]);
return 0;
}
F - Fraction of Fractal
对于原图,如果第 行最左边是黑的,最右边也是黑的,就说有一个“左右接口”。如果第 列最上面最下面都是黑的,就说有一个“上下接口”。
记原图形中黑色块的数量为 。
或 答案都是1。
若“左右接口”和“上下接口”都有,答案是1。
若都没有,答案是
剩下的情况:
设所有的1级分形是一个点,如果两个1级分形之间可以互相到达,就说它们之间有一条边。由于只有上下接口或者只有左右接口,所以可以看作是若干条链。我们发现边数-点数就是连通块数目。
设
表示
级分形的点数,
表示
级分形边数,
表示上下接口或者左右接口的总数,
表示满足(如果只有上下接口,就是mp[i][j]=='#'&&mp[i-1][j]=='#'
,如果只有左右接口,就是mp[i][j]=='#'&&mp[i][j-1]=='#'
)的数对个数。
则:
用矩阵乘法即可。
#include<bits/stdc++.h>
using namespace std;
#define RI register int
typedef long long LL;
const int mod=1e9+7;
int n,m,a1,a2,b,s;LL K;
char mp[1005][1005];int tmp[3];
int ksm(int x,LL y) {
int re=1;
for(;y;y>>=1,x=1LL*x*x%mod) if(y&1) re=1LL*re*x%mod;
return re;
}
struct matrix{int t[3][3];}X,re;
int qm(int x) {return x>=mod?x-mod:x;}
matrix operator * (matrix A,matrix B) {
matrix C;
for(RI i=0;i<3;++i)
for(RI j=0;j<3;++j) C.t[i][j]=0;
for(RI k=0;k<3;++k)
for(RI i=0;i<3;++i)
for(RI j=0;j<3;++j)
C.t[i][j]=qm(C.t[i][j]+1LL*A.t[i][k]*B.t[k][j]%mod);
return C;
}
void work() {
for(RI i=0;i<3;++i) re.t[i][i]=1;
X.t[0][0]=X.t[1][1]=s,X.t[1][2]=1,X.t[2][2]=a1;
for(LL i=K-2;i;i>>=1,X=X*X) if(i&1) re=re*X;
int V=0,E=0;
tmp[0]=s,tmp[1]=b,tmp[2]=a1*b;
for(RI i=0;i<3;++i) V=qm(V+1LL*re.t[0][i]*tmp[i]%mod);
for(RI i=0;i<3;++i) E=qm(E+1LL*re.t[1][i]*tmp[i]%mod);
printf("%d\n",qm(V-E+mod));
}
int main()
{
scanf("%d%d%lld",&n,&m,&K);
if(K<=1) {puts("1");return 0;}
for(RI i=1;i<=n;++i) scanf("%s",mp[i]+1);
for(RI i=1;i<=m;++i) if(mp[1][i]=='#'&&mp[n][i]=='#') ++a1;
for(RI i=1;i<=n;++i) if(mp[i][1]=='#'&&mp[i][m]=='#') ++a2;
for(RI i=1;i<=n;++i)
for(RI j=1;j<=m;++j) if(mp[i][j]=='#') ++s;
if(a1&&a2) {puts("1");return 0;}
else if(!a1&&!a2) {printf("%d\n",ksm(s,K-1));return 0;}
if(a1) {
for(RI i=1;i<n;++i)
for(RI j=1;j<=m;++j)
b+=(mp[i][j]=='#'&&mp[i+1][j]=='#');
}
else {
for(RI i=1;i<=n;++i)
for(RI j=1;j<m;++j)
b+=(mp[i][j]=='#'&&mp[i][j+1]=='#');
}
a1=a1|a2,work();
return 0;
}