题目链接:http://codeforces.com/contest/1151
A. Maxim and Biology
暴力每个做起点即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mx = 1e2 + 10;
char s[mx];
int main(){
int n,ans = 1e9;
scanf("%d%s",&n,s);
for(int i=0;i<=n-4;i++){
int a = abs(s[i]-'A');
a = min(a,26-a);
int b = abs(s[i+1]-'C');
b = min(b,26-b);
int c = abs(s[i+2]-'T');
c = min(c,26-c);
int d = abs(s[i+3]-'G');
d = min(d,26-d);
ans = min(ans,a+b+c+d);
}
printf("%d\n",ans);
return 0;
}
B. Dima and a Bad XOR
枚举一个二进制位数,看是否在每个行选择一个数,使得这个二进制位最后是1。那么很显然如果有一行对一个二进制位数的贡献既可以是1也可以是0,那么n行组成的对该二进制位数的贡献肯定可以是奇数。
还有就是一个细节问题,看代码就清楚了。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mx = 5e2 + 10;
int n,m,a[mx][mx],ans[mx];
bool vis[mx];
int find(int x,int d,bool f){
for(int i=1;i<=m;i++){
bool ok = a[x][i]&(1<<d);
if(f==ok) return i;
}
}
void solve(){
for(int i=0;i<10;i++){
int d = 0;bool w = 0;
memset(vis,0,sizeof(vis));
for(int j=1;j<=n;j++){
int c = 0;
for(int k=1;k<=m;k++){
if(a[j][k]&(1<<i))
c++;
}
if(c==m) d++;
if(c&&c!=m) w = vis[j] = 1;
}
if((d&1)||w){
puts("TAK");
bool f = !(d&1);
for(int j=1;j<=n;j++){
if(!vis[j]) printf("1 ");
else printf("%d ",find(j,i,f)),f=0;
}
return;
}
}
puts("NIE");
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
scanf("%d",a[i]+j);
}
solve();
return 0;
}
C. Problem for Nazar
这题其实也不难,按照题目说的做,然后二进制倍增+等差数列求和就是了。注意一点点细节就好了。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mx = 5e2 + 10;
const int mod = 1e9 + 7;
ll l,r,siz[2];
bool vis[mx];
void add(ll &ans,ll len,ll c,int b){
b ^= 1;
len %=mod,c %= mod;
ans += ((2*c-(1<<b))*len%mod+len*len%mod);
ans %= mod;
}
int main(){
scanf("%lld%lld",&l,&r);
int bit = 0;
ll p = 0,c,len,ans = 0;
while(p+(1ll<<bit)<l){
p += (1ll<<bit);
siz[bit&1] += (1ll<<bit);
bit++;
}
if(p+(1ll<<bit)>=r){
len = (r-l+1);
c = (siz[bit&1]+l-p);
add(ans,len,c,bit&1);
printf("%lld\n",ans%mod);
return 0;
}
len = (1ll<<bit)-(l-p)+1;
c = (siz[bit&1]+l-p);
add(ans,len,c,bit&1);
p += (1ll<<bit),siz[bit&1] += (1ll<<bit),bit++;
while(p+(1ll<<bit)<r){
add(ans,1ll<<bit,siz[bit&1]+1,bit&1);
p += (1ll<<bit);
siz[bit&1] += (1ll<<bit);
bit++;
}
len = r - p;c = siz[bit&1] + 1;
add(ans,len,c,bit&1);
printf("%lld\n",ans);
return 0;
}
D. Stas and the Queue at the Buffet
这题我感觉放在D不是那么合适,化一个公式然后排序贪心就ok了。
将原式ai⋅(j−1)+bi⋅(n−j) 化为 (ai-bi) *j - ai + bi*n。然后发现后面两个式子是和j没有关系的,直接求出。
对于第一个式子,把ai-bi看做整体,排个序,值大的占小头,值小的占大头,就可以保证最小值啦。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mx = 1e5 + 10;
const int mod = 1e9 + 7;
int n,c[mx];
int main(){
scanf("%d",&n);
ll ans = 0;
int a,b;
for(int i=1;i<=n;i++){
scanf("%d%d",&a,&b);
ans += 1ll*b*n - a;
c[i] = a - b;
}
sort(c+1,c+1+n);
for(int i=1;i<=n;i++) ans += 1ll*c[i]*(n-i+1);
printf("%lld\n",ans);
return 0;
}
E. Number of Components
首先要做的是缩点,也就是对于相等的数连续的一块,缩成一个点,显然对结果是不影响的。接下来我们再具体分析。
如果i位置的值被留下:
1.i-1和i+1被留下,对于结果-> +1-2 = -1;
2.i-1被留下,对于结果 +1-1 = 0
3.i+1被留下,对于结果 +1-1 = 0
3.i+1和i-1都没有被留下,对于结果 +1。
因此,我们可以看做每个点i的初始贡献是1,如果它的相邻点也参与了贡献并且它的值小于a[i](防止被重复计算),那么就给i点另外加一个-1的贡献。计算i和他的相邻点是否同时贡献也就是计算他们的值是否都在区间中,这些都可以利用组合数轻松求出。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mx = 1e5 + 10;
const int mod = 1e9 + 7;
int n,a[mx];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",a+i);
}
int c = 1;
for(int i=2;i<=n;i++){
if(a[i]!=a[c]) a[++c] = a[i];
}
a[c+1] = a[0] = n+1;
ll ans = 0;
for(int i=1;i<=c;i++){
ans += 1ll*a[i]*(n-a[i]+1);
if(a[i-1]<a[i]){
ans -= 1ll*a[i-1]*(n-a[i]+1);
}
if(a[i+1]<a[i]){
ans -= 1ll*a[i+1]*(n-a[i]+1);
}
}
printf("%lld\n",ans);
return 0;
}
F. Sonya and Informatics
假设n个数中0有c个,1有d个,c+d = n。最后的结果肯定是钱c个数要是0,后d个数要是1。
那么我们就可以考虑一个转态f[i][j],表示交换了j次之后,前c个数中有i个数是1的方案数。
很明显f[i][j]可以转移到:
,
,
。
但是我们发现j过于大,不可能这么维护一个二维数组,所以取考虑一个矩阵快速幂,这样就可以把第二维去掉了,而且我们发现第一维的大小最多是min(c,d)<=50。
所以最后时间复杂度可以做到O(
*log(K))
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mx = 1e2 + 10;
const int mod = 1e9 + 7;
const int N = 50;
int n,a[mx],K;
struct node
{
int mat[55][55];
}base;
node matr(node &p1,node &p2)
{
node ret;
memset(&ret,0,sizeof(node));
for(int k=0;k<=N;k++){
for(int i=0;i<=N;i++){
if(p1.mat[i][k]);
for(int j=0;j<=N;j++){
ret.mat[i][j] += 1ll*p1.mat[i][k]*p2.mat[k][j]%mod;
ret.mat[i][j] %= mod;
}
}
}
return ret;
}
node mpow(int y,int p){
node ans;
memset(&ans,0,sizeof(node));
ans.mat[0][p] = 1;
while(y){
if(y&1) ans = matr(ans,base);
base = matr(base,base);
y >>= 1;
}
return ans;
}
ll qpow(ll x,ll y){
ll ans = 1;
while(y){
if(y&1) ans = ans*x%mod;
y >>= 1;
x = x*x%mod;
}
return ans;
}
int main(){
scanf("%d%d",&n,&K);
int c = 0,d = 0,b = 0;
for(int i=1;i<=n;i++){
scanf("%d",a+i);
if(a[i]) d++; else c++;
}
for(int i=1;i<=c;i++) if(a[i]) b++;
base.mat[0][0] = c*(c-1) / 2 + d*(d-1) / 2;
base.mat[1][0] = 1;
for(int i=1;i<=min(c,d);i++){
base.mat[i-1][i] = (c-i+1)*(d-i+1);
base.mat[i][i] = c*(c-1) / 2 + d*(d-1) / 2;
base.mat[i][i] += (c-i)*i + (d-i)*i;
base.mat[i+1][i] = (i+1)*(i+1);
}
ll ans = mpow(K,b).mat[0][0];
printf("%lld\n",ans*qpow(qpow(n*(n-1)/2,K),mod-2)%mod);
return 0;
}