B Binary Vector
可以直接通过样例找规律推递推式,其证明如下。
#include <iostream>
#include <stdio.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int maxn=2e7+5;
int T,n;
long long f[maxn],Xor[maxn];
ll quickpow(ll x,ll y)
{
ll sum=1;
while(y)
{
if(y&1)
sum=(sum*x)%mod;
y>>=1;
x=(x*x)%mod;
}
return sum;
}
int main()
{
ll q=quickpow(2,mod-2);
ll now=2;
ll inv=q;
f[0]=1;
for(int i=1;i<=2e7;++i)
{
f[i]=((f[i-1]*(now-1)%mod)*inv)%mod;
now=now*2%mod;
inv=inv*q%mod;
Xor[i]=Xor[i-1]^f[i];
}
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
printf("%lld\n",Xor[n]);
}
return 0;
}
C Combination of Physics and Math
这题就是要证以下结论。
然后我们比较所有单列的情况,取最大值。
#include <bits/stdc++.h>
using namespace std;
const int maxn=205;
const double eps=1e-8;
int T;
int n,m,k;
double a[maxn];
double sum[maxn];
int main()
{
scanf("%d",&T);
while(T--)
{
double ma=0.0;
scanf("%d %d",&n,&m);
for(int i=1;i<=m;++i)
sum[i]=0.0;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
scanf("%lf",&a[j]);
sum[j]+=a[j];
ma=max(ma,sum[j]/a[j]);
}
}
printf("%.8lf\n",ma);
}
return 0;
}
E Easy Construction
本题,也是通过几组数据找到规律。我们发现长度为n的子序列就是P本身,因此其加和必须满足 n*(n+1)/2%n=k。我们分奇数偶数讨论。当n为奇数时,n+1为偶数,那么 k=0 才能使等式成立。当n为偶数时,当 k=n/2 才能使等式成立。当然,现在只是必要条件,我们先找构造。当n为偶数,其构造P为{n,n/2,n-1,1…}。当n为奇数,其构造P为{n,n-1,1…}。我们可以发现,只要构造成这样,那么每种长度的情况都能一个子序列之和%n=k,这个与一个数肯定能被2 n相加表示一样。那么找到构造的话,就是充要条件了。
#include <iostream>
#include <stdio.h>
using namespace std;
int n,k;
int main()
{
scanf("%d %d",&n,&k);
if(n&1)
{
if(k)
{
puts("-1");
}
else
{
printf("%d",n);
int cnt=0;
for(int i=2;i<=n;++i)
{
if(i%2==0)
{
++cnt;
printf(" %d",n-cnt);
}
else
printf(" %d",cnt);
}
}
}
else
{
if(k!=n/2)
{
puts("-1");
}
else
{
printf("%d %d",n,n/2);
int cnt=0;
for(int i=3;i<=n;++i)
{
if(i&1)
{
++cnt;
printf(" %d",n-cnt);
}
else
{
printf(" %d",cnt);
}
}
}
}
return 0;
}
G Grid Coloring
一个构造题,这里只给出一种构造方法,首先,buzhengchun=1,k=1,k不整除2n(n+1),是没有方案的。然后,如果k不整除n,那么直接顺序放就可以了,这样相邻的横边和纵边肯定颜色不同,并且因为k不整除n,那么1*1的环内就不会是相同颜色。如果k|n,那么顺序放的话,1*1的环内就会有相同颜色,我们只需要在偶数行或列,将防止顺序移动一位即可。
#include <iostream>
#include <stdio.h>
using namespace std;
int T,n,k;
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d %d",&n,&k);
if(n==1||k==1||2*n*(n+1)%k>0)
{
puts("-1");
continue;
}
if(n%k==0)
{
int c=0;
for(int i=1;i<=2*(n+1);++i)
{
int last=c;
for(int j=1;j<=n;++j)
{
last=last%k+1;
if(j!=n)
printf("%d ",last);
else
printf("%d\n",last);
}
c^=1;
}
}
else
{
int last=0;
for(int i=1;i<=2*(n+1);++i)
{
for(int j=1;j<=n;++j)
{
last=last%k+1;
if(j!=n)
printf("%d ",last);
else
printf("%d\n",last);
}
}
}
}
return 0;
}
H Harmony Pairs
数位dp,dp[pos][diff][lim1][lim2]代表A和B在已找到pos位,diff代表S(A)-S(B),可能为负数,因此要+1000,lim1代表当前B是否等于N,lim2代表当前A是否等于B。
#include <iostream>
#include <stdio.h>
#include <cstring>
using namespace std;
const int maxn=105;
const long long mod=1e9+7;
long long dp[maxn][2001][2][2];
char str[maxn];
int a[maxn];
long long dfs(int pos,int diff,int lim1,int lim2)
{
if(!pos)
{
return 1ll*(diff>1000);
}
if(dp[pos][diff][lim1][lim2]!=-1)
return dp[pos][diff][lim1][lim2];
int up1=lim1?a[pos]:9;
long long ans=0;
for(int i=0;i<=up1;++i)//B
{
int up2=lim2?i:9;
for(int j=0;j<=up2;++j)
{
ans+=dfs(pos-1,diff+j-i,lim1&(i==a[pos]),lim2&(i==j));
ans%=mod;
}
}
dp[pos][diff][lim1][lim2]=ans;
return ans;
}
void init()
{
memset(dp,-1,sizeof(dp));
}
int main()
{
init();
scanf("%s",str+1);
int len=strlen(str+1);
for(int i=1;i<=len;++i)
a[len-i+1]=str[i]-'0';
printf("%lld\n",dfs(len,1000,1,1));
return 0;
}
K K-Bag
我们可以发现,如果有两个数相等,且他们之间的距离小于k,那么这两个数间的所有数,都可能作为后一个数所在序列的开头,因此,这些元素权值+1,并且此时限制数+1,如果一个数作为某个序列的开头,那么其%k之后的位置,便是第一个完整序列的开头,那么将所有位置的权值加到其%k之后的位置,如果能在前1~k个位置,找到与限制数相等的权值(意味着以此为第一序列开头,满足之后所有限制),那么就是k-bag,否则就不是。
但是,如果每次直接暴力权值+1,会导致复杂度太大,我们可以利用差分,例如区间[l,r]元素+1,那么差分之后,就是l所在位置+1,r+1所在位置-1。这样每次就是O(1)的复杂度了。
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
int T,n,k;
int a[maxn],vis[maxn],num[maxn];
map<int,int>mp;
int cnt;
void init(int n)
{
cnt=0;
mp.clear();
for(int i=1;i<=n;++i)
num[i]=vis[i]=0;
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d %d",&n,&k);
init(n);
for(int i=1;i<=n;++i)
{
scanf("%d",&a[i]);
if(mp[a[i]])
{
if(i-mp[a[i]]<k)
{
cnt++;
vis[mp[a[i]]+1]++;
vis[i+1]--;
}
}
mp[a[i]]=i;
}
int pre=0;
bool flag=0;
for(int i=1;i<=n;++i)
{
pre+=vis[i];
num[i%k+1]+=pre;
}
for(int i=1;i<=n;++i)
{
if(num[i]==cnt)
{
flag=true;
break;
}
}
if(flag)
puts("YES");
else
puts("NO");
}
return 0;
}