A、Dong Zhi
直接输出即可。
#include
using namespace std;
int main()
{
printf("Let's eat dumplings");
return 0;
}
B、The flower
利用
储存长为
的字符串,暴力计算即可。
#include
using namespace std;
int main(){
string s;
int k;
cin>>s>>k;
unordered_map mmp;
set st;
int n=(int)s.length();
for(int i=k-1;i
string now=s.substr(i-(k-1),k);
mmp[now]++;
st.insert(now);
}
set ans;
for(auto v:st){
if(mmp[v]>2){
ans.insert(v);
}
}
cout<
for(auto v:ans) cout<
return 0;
}
C、Xor Path
计算从根节点到每个节点的异或和,同时计算倍增。然后利用倍增可以实现
的查询。
#include
using namespace std;
const int N = 1e6+100;
vector G[N];
int pre[N],a[N],par[N];
long long bit[30];
int f[N][30];
int depth[N];
void init(){
bit[0]=1;
for(int i=1;i<=29;i++) bit[i]=(bit[i-1]<<1);
}
void dfs(int u,int par){
depth[u]=depth[par]+1;
f[u][0]=par;
for(int i=1;bit[i]<=depth[u];i++) f[u][i]=f[f[u][i-1]][i-1];
for(int v:G[u]){
if(v!=par) dfs(v,u);
}
}
int lca(int x,int y){
if(depth[x]
for(int i=29;i>=0;i--){
if(depth[x]-depth[y]>=bit[i]){
x=f[x][i];
}
}
if(x==y) return x;
for(int i=29;i>=0;i--){
if(depth[x]>=(1<
x=f[x][i];
y=f[y][i];
}
}
return f[x][0];
}
void DFS1(int u,int fa){
par[u]=fa;
pre[u]=pre[fa]^a[u];
for(int v:G[u]){
if(v==fa) continue;
DFS1(v,u);
}
}
int main(){
int n,u,v,q;
cin>>n;
init();
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=0;i<=n;i++) G[i].clear();
for(int i=1;i<=n-1;i++){
cin>>u>>v;
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1,0);
DFS1(1,0);
int x,y;
cin>>q;
while(q--){
cin>>x>>y;
int c=lca(x,y);
int f=par[c];
cout<
}
return 0;
}
D、LaunchPad
开两个数组分别记录当前行或列是否有操作,再开一个二维数组计算每个灯在操作后的亮灭情况(用来调整行和列所带来的一次操作而不是两次操作)。
#include
using namespace std;
#define ll long long
const int maxn=1000+10;
int a[maxn],b[maxn];
int c[maxn][maxn];
int main()
{
int n,m,q;
scanf("%d %d",&n,&m);
scanf("%d",&q);
while(q--){
int u,v;
scanf("%d %d",&u,&v);
c[u][v]^=1;
a[u]^=1;
b[v]^=1;
}
int ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
ans+=a[i]^b[j]^c[i][j];
}
}
printf("%d\n",ans);
return 0;
}
E、Morse code
长度为
的
种情况已经全部出现过,长度为
的
种情况也已经出现过,因此我们一定能够利用长度为
或
的字母去填充,因此答案就是
。
此处给出
做法,以供学习。
#include
using namespace std;
const int maxn=1e6+10;
mapmp;
string code[100];
char s[maxn];
int dp[maxn];
void init(){
code[1]=".-"; code[2]="-..."; code[3]="-.-."; code[4]="-..";
code[5]="..-."; code[6]="--."; code[7]="....";
code[8]=".."; code[9]=".---"; code[10]="-.-"; code[11]=".-..";
code[12]="--"; code[13]="-."; code[14]="---"; code[15]=".--.";
code[16]="--.-";code[17]=".-."; code[18]="...";
code[19]="..-"; code[20]="...-"; code[21]=".--";code[22]="-..-";
code[23]="-.--"; code[24]="--..";
for(int i=1;i<=24;i++){
int num=0;
for(int j=0;j
mp[num]++;
}
}
int cal(int a,int b){
int num=0;
for(int i=a;i<=b;i++) num=num*100+s[i];
return mp[num]?1:0;
}
void solve(){
scanf("%s",s);
int n=strlen(s);
for(int i=0;i
dp[i]=0;
for(int j=1;j<=4;j++){
int y=i-j;
dp[i]=max(dp[i],dp[i-j]+cal(i-j+1,i));
}
}
printf("%d\n",dp[n-1]);
}
int main()
{
init();
int t;
scanf("%d",&t);
while(t--){
solve();
}
return 0;
}
F、Puzzle
原签到题。
#include
using namespace std;
#define ll long long
#define pii pair
const ll maxn=1000000+10;
const ll INF=0x3f3f3f3f3f3f3f3f;
const ll mod=1e9+7;
int a[100];
void init(){
a[0]=1;
a[1]=0;
a[2]=0;
a[3]=0;
a[4]=1;
a[5]=0;
a[6]=1;
a[7]=0;
a[8]=2;
a[9]=1;
}
int main()
{
init();
int t;
scanf("%d",&t);
while(t--){
ll x;
scanf("%lld",&x);
if(x==0) printf("1\n");
else{
int num=0;
while(x){
num+=a[x%10];
x/=10;
}
printf("%d\n",num);
}
}
return 0;
}
G、Triangle tower
尖向上的小三角形能够组成一个杨辉三角,向下的又能够组成一个杨辉三角,因此分情况计算即可。
#include
using namespace std;
#define ll long long
const ll mod=1e9+7;
const int maxn=100000+10;
ll fac[maxn];
void init(){
fac[0]=1;
for(int i=1;i<=maxn;i++) fac[i]=fac[i-1]*i%mod;
}
ll qp(ll a,ll b){
ll res=1;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
ll c(int n,int m){
return fac[n]*qp(fac[m],mod-2)%mod*qp(fac[n-m],mod-2)%mod;
}
ll solve(int n,int m){
n--;
if(m%2==0) n--;
m=(m-1)/2;
printf("%lld\n",c(n,m));
}
int main()
{
int t,n,m;
scanf("%d",&t);
init();
while(t--){
scanf("%d %d",&n,&m);
solve(n,m);
}
return 0;
}
H、Kingdom of Mathematics
应该是整个比赛里面最难的一个题?
Part1
$
g(x)=f(x)+x
$
Part2
可以发现,
的二进制表示位数为
位,而且在
足够大时,可以发现高位数几乎全为
。我们将
每两项进行异或
,可以发现
,因此前偶数项我们就可以用类似的方法计算出结果
,结果为各项
部分相加,最后一位判断总共有多少对即可。
对于奇数
,我们已知前
位的值
,我们将其分为两部分,低位部分位
影响到的部分(即与高位全一部分的分界线),高位部分为全一部分。然后分开计算即可。
#include
using namespace std;
#define ll long long
const int maxn=1000000+10;
const ll mod=1e9+7;
ll T,n;
ll qp(ll a,ll b){
ll res=1;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
//等比数列前x项之和 第一项为1
ll judge(ll x){
ll sum=(qp(4,x)-1+mod)%mod;
return 2*sum*qp(3,mod-2)%mod;
}
//二进制位数
ll bits(ll x){
ll sum=0;
while(x){
sum++;
x>>=1;
}
return sum;
}
ll revise(ll x,ll step){
ll pos=1;
stackst;
for(int i=1;i<=step;i++){
if(i%2==0) st.push(1-(x&1));
else st.push(x&1);
x>>=1;
}
ll sum=0;
while(!st.empty()){
sum=sum*2+st.top();
st.pop();
}
return sum;
}
int main()
{
scanf("%lld",&T);
while(T--){
ll res;
scanf("%lld",&n);
if(n&1){
ll vis=bits(n);
//高位没被影响到的的值
res=judge((n-vis)/2);
if((n-vis)&1) res=(res*2+1)%mod;
res=res*qp(2,vis)%mod;
//低位被异或的值
res=(res+revise((1ll<
//最后一位加or减
if((n/2)&1){
if(n&1) res=(res-1+mod)%mod;
else res=(res+1)%mod;
}
}
else{
res=judge(n/2);
if((n/2)&1) res=(res+1)%mod;
}
printf("%lld\n",res);
}
return 0;
}
I、HPU's birthday
暴力计算每个
的贡献即可,假如某个
前面有
个
,那么它的贡献即为
。
#include
using namespace std;
#define ll long long
const ll mod=1e9+7;
int q[100];
int main()
{
int t;
scanf("%d",&t);
while(t--){
int n;
scanf("%d",&n);
int num=0;
ll ans=0;
ll x=n;
while(x){
q[num++]=x&1;
x>>=1;
}
x=0;
for(int i=0;i
for(int j=num-1;j>=0;j--){
if(q[j]) x++;
else ans=(ans+x*(x-1)/2)%mod;
}
}
printf("%lld\n",ans);
}
return 0;
}
以下为
的解法:
#include
using namespace std;
#define ll long long
const ll mod=1e9+7;
int q[100];
ll qp(ll a,ll b){
ll res=1;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
ll cal(ll x,ll n,ll a){
ll ans=0;
ans=n*x*x%mod;
ans=(ans+(n-1)%mod*n%mod*x%mod*a%mod);
ans=(ans+(n-1)%mod*n%mod*(2*n-1)%mod*qp(2,mod-2)%mod*a%mod*a%mod);
ans=(ans-n%mod*x%mod+mod)%mod;
ans=(ans-(n-1)%mod*n%mod*qp(2,mod-2)%mod*a%mod+mod)%mod;
return ans;
}
int main()
{
ll inv2=qp(2,mod-2);
ll t;
scanf("%lld",&t);
while(t--){
ll n;
scanf("%lld",&n);
ll num=0,ans=0,x=n;
ll one=0;
while(x){
if(x&1) one++;
q[num++]=x&1;
x>>=1;
}
x=0;
for(int i=num-1;i>=0;i--){
if(q[i]) x++;
else ans=(ans+cal(x,n,one));
}
printf("%lld\n",ans*inv2%mod);
}
return 0;
}
J、Max Sum
我们首先记录前缀和数组
和后缀和数组
,然后对其建两棵线段树。
对于第
个位置,我们计算区间
的最小前缀和和
的最小后缀和,数组总和减去这两部分的值即为第
个位置的最大值。由于数据范围的原因,还要特别处理一下边界条件。
#include
using namespace std;
#define ll long long
const int maxn=1000000+10;
const int INF=0x3f3f3f3f;
int a[maxn];
ll pre[maxn],nxt[maxn];
int k[maxn];
int N;
struct Tree{
ll x[maxn];
void init(int x){
N=1;
while(N<=x*2) N*=2;
}
void update(int k,int q){
k+=N-1;
x[k]=q;
while(k){
k=(k-1)/2;
x[k]=min(x[k*2+1],x[k*2+2]);
}
}
ll query(int a,int b,int l,int r,int k){
if(r
if(a<=l && r<=b) return x[k];
else{
ll vl=query(a,b,l,(l+r)/2,k*2+1);
ll vr=query(a,b,(l+r)/2+1,r,k*2+2);
return min(vl,vr);
}
}
}tp,tn;
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&k[i]);
tp.init(n);
ll sum=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
sum+=a[i];
tp.update(i,sum);
}
sum=0;
for(int i=n;i>=1;i--){
sum+=a[i];
tn.update(i,sum);
}
ll ans=0;
for(int i=1;i<=n;i++){
ans+=sum;
ans-=tp.query(max(i-k[i]-1,0),max(i-1,0),0,N-1,0);
ans-=tn.query(min(i+1,n+1),min(i+k[i]+1,n+1),0,N-1,0);
}
printf("%lld\n",ans);
return 0;
}
K、Restore Expressions
要使中的贡献最小,首先把除了第一项以外的值全部置为
,仅考虑第一项的值即可,假设表达式的值为
,计算出两个式子第一项值为
,那么我们就进行如下操作:若其中一项不为正数,则两个数均加上一个值使得两个数均为正数。这样可以使得两个式子值相同且贡献尽可能的小。
#include
using namespace std;
const int maxn=2000000+10;
char s[maxn],t[maxn];
void solve(){
int n;
scanf("%d",&n);
scanf("%s %s",s,t);
int a=0,b=0;
for(int i=0;i
if(s[i]=='-') a++;
else a--;
if(t[i]=='-') b++;
else b--;
}
int prea,preb;
prea=a+max(1-min(a,b),0);
preb=b+max(1-min(a,b),0);
printf("%d %d\n",0,prea+preb+n*2);
printf("%d",prea);
for(int i=1;i<=n;i++) printf(" %d",1);
printf("\n");
printf("%d",preb);
for(int i=1;i<=n;i++) printf(" %d",1);
printf("\n");
}
int main()
{
solve();
return 0;
}