A - 数字权重
题目大意:
一个(n)位的数字。设第(i)位的数为(a_i),其中(a_1)为最高位,(a_n)为最低位,(k)为给定的数字。求同时满足满足以下两个条件的数的个数:
- 不含前导(0);
- (sum_{i=2}^n(a_i-a_{i-1})=k)。
(n,|k|le10^{13})。
思路:
对和式稍加变形得(a_n-a_1=k),因此我们只需要考虑(a_1)和(a_n),其余数位(0sim 9)随便放即可。
源代码:
#include<cstdio>
#include<cctype>
#include<algorithm>
using int64=long long;
inline int64 getint() {
register char ch;
register bool neg=false;
while(!isdigit(ch=getchar())) neg|=ch=='-';
register int64 x=ch^'0';
while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
return neg?-x:x;
}
constexpr int mod=1e9+7;
inline int power(int a,int64 k) {
int ret=1;
for(;k;k>>=1) {
if(k&1) ret=(int64)ret*a%mod;
a=(int64)a*a%mod;
}
return ret;
}
int main() {
const int64 n=getint(),k=getint();
if(std::abs(k)>9) {
puts("0");
return 0;
}
int ans=power(10,n-2);
if(k>=0) ans=ans*(9-k)%mod;
if(k<0) ans=ans*(10+k)%mod;
printf("%d
",ans);
return 0;
}
B - 毒瘤xor
同CC-XXOR。
C - 硬币游戏
题目大意:
A和B各有一行长度为(2n(nle10^6))的01序列,A先取,每次只能取两个人之前都没取过的位置,这样(n)次后两个人就得到了长度为(n)的数字串,谁的字典序大谁就赢了。若两人都按照最优策略,问最后谁赢(或平手)。
思路:
每次贪心取未被选择位置上的(1),如果有很多(1)那么优先取对方也是(1)的。用堆来维护,时间复杂度(mathcal O(nlog n))。
源代码:
#include<queue>
#include<cstdio>
#include<cctype>
inline int getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'0';
while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
return x;
}
inline bool getval() {
register char ch;
while(!isalpha(ch=getchar()));
return ch=='U';
}
const int N=2e6+1;
bool a[N],b[N],mark[N];
struct Node {
bool a,b;
int id;
bool operator < (const Node &rhs) const {
if(a^rhs.a) return !a;
if(b^rhs.b) return !b;
return id<rhs.id;
}
};
std::priority_queue<Node> q[2];
int main() {
const int n=getint();
for(register int i=1;i<=n*2;i++) a[i]=getval();
for(register int i=1;i<=n*2;i++) b[i]=getval();
for(register int i=1;i<=n*2;i++) {
q[0].push((Node){a[i],b[i],i});
q[1].push((Node){b[i],a[i],i});
}
for(register int i=1;i<=n;i++) {
while(mark[q[0].top().id]) q[0].pop();
a[i]=q[0].top().a;
mark[q[0].top().id]=true;
while(mark[q[1].top().id]) q[1].pop();
b[i]=q[1].top().a;
mark[q[1].top().id]=true;
}
for(register int i=1;i<=n;i++) {
if(a[i]==b[i]) continue;
puts(a[i]?"clccle trl!":"sarlendy tql!");
return 0;
}
puts("orz sarlendy!");
return 0;
}
D - 粉樱花之恋
题目大意:
求斐波那契数列前(n(nle10^{18}))项和。
思路:
找规律可以发现前(n)项和(F(n)=f(n+3)-1),因此直接矩阵快速幂或者折半公式即可。
时间复杂度(mathcal O(nlog n))。
源代码:
#include<cstdio>
#include<cctype>
#include<unordered_map>
using int64=long long;
inline int64 getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int64 x=ch^'0';
while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
return x;
}
const int64 mod=998244353;
std::unordered_map<int64,int> m;
inline int64 sqr(const int64 &x) {
return x*x;
}
int64 f(const int64 &n) {
if(m[n]) return m[n];
if(n==1||n==2) return m[n]=1;
if(n&1) return m[n]=(sqr(f(n/2+1))+sqr(f(n/2)))%mod;
return m[n]=(f(n/2-1)*2+f(n/2))*f(n/2)%mod;
}
int main() {
printf("%lld
",f(getint()+3)-1);
return 0;
}
E - 符合条件的整数
题目大意:
求([2^n,2^m)(n,mle65))内满足(xequiv1pmod{7})的(x)个数。
思路:
使用__int128
直接算即可。
源代码:
#include<cstdio>
#include<cctype>
#include<iostream>
typedef unsigned __int128 uint128;
std::ostream &operator <<(std::ostream &os,const uint128 &x) {
if(x>=10) os<<x/10;
return os<<int(x%10);
}
inline int getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'0';
while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
return x;
}
int main() {
const int n=getint(),m=getint();
std::cout<<(((uint128)1<<m)-2)/7-(((uint128)1<<n)-2)/7<<std::endl;
return 0;
}
F - 可爱即正义
题目大意:
给你一个字符串(s),问是否能通过交换两个字符使得其不包括suqingnianloveskirito
作为子串。
思路:
哈希以后统计suqingnianloveskirito
的出现次数,并记录出现位置,分情况讨论即可。
源代码:
明明很多锅(比如(cnt=0)时交换前两个可能产生新的suqingnianloveskirito
),但还是过了。
#include<cstdio>
#include<cstring>
using uint64=unsigned long long;
const int N=1e6+2,base=31;
char s[N];
const char t[23]=" suqingnianloveskirito";
uint64 hash[N],pwr[N],tmp;
int pos[N];
inline uint64 calc(const int &i) {
return hash[i]-hash[i-21]*pwr[21];
}
int main() {
scanf("%s",&s[1]);
const int n=strlen(&s[1]);
if(n==1) {
puts("No");
return 0;
}
for(register int i=pwr[0]=1;i<=n;i++) {
pwr[i]=pwr[i-1]*base;
hash[i]=hash[i-1]*base+s[i]-'a'+1;
}
for(register int i=1;i<=21;i++) {
tmp=tmp*base+t[i]-'a'+1;
}
int cnt=0;
for(register int i=1;i<=n;i++) {
if(i>=21&&calc(i)==tmp) {
pos[++cnt]=i;
}
}
if(cnt==0) {
puts("Yes
1 2
");
return 0;
}
if(cnt==1) {
puts("Yes");
printf("%d %d
",pos[1],pos[1]-1);
return 0;
}
if(cnt==2) {
puts("Yes");
printf("%d %d
",pos[1],pos[2]-1);
return 0;
}
puts("No");
return 0;
}