A Matirx
对于操作1,2;
不需要直接交换矩阵,把矩阵行列交换的记录记下来,相当于给它弄了个指针,输出按照指针指向的行列输出;
3,4操作同。
代码:
/* ***********************************************
Author :angon
************************************************ */
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <stack>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
#define REP(i,k,n) for(int i=k;i<n;i++)
#define REPP(i,k,n) for(int i=k;i<=n;i++)
#define scan(d) scanf("%d",&d)
#define scann(n,m) scanf("%d%d",&n,&m)
#define mst(a,k) memset(a,k,sizeof(a));
#define LL long long
#define maxn 1005
#define mod 100000007
int a[maxn][maxn];
int n,m,q;
int t1[maxn],t2[maxn],d1[maxn],d2[maxn];//记录行列交换的位置和加的值
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T;
scan(T);
while(T--)
{
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scan(a[i][j]);
for(int i=0;i<=n;i++) t1[i]=i,d1[i]=0;
for(int i=0;i<=m;i++) t2[i]=i,d2[i]=0;
int x,y,f;
while(q--)
{
scanf("%d%d%d",&f,&x,&y);
if(f==1)
swap(t1[x],t1[y]);
else if(f==2)
swap(t2[x],t2[y]);
else if(f==3)
d1[t1[x]]+=y;
else
d2[t2[x]]+=y;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
printf("%d%c",a[t1[i]][t2[j]]+d1[t1[i]]+d2[t2[j]],j==m?'\n':' ');
}
return 0;
}
B Sting
如果字串(i , j)是满足要求的子串,那么子串(i, k) ( k>j )也必然是满足要求的子串;所以,对于每一个左边界i,只需找到最小的满足要求的 j ,ans += len-j ;就是答案。
我写的代码很搓。。
/* ***********************************************
Author :angon
************************************************ */
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <stack>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
#define REP(i,k,n) for(int i=k;i<n;i++)
#define REPP(i,k,n) for(int i=k;i<=n;i++)
#define scan(d) scanf("%d",&d)
#define scann(n,m) scanf("%d%d",&n,&m)
#define mst(a,k) memset(a,k,sizeof(a));
#define LL long long
#define maxn 1000005
#define mod 100000007
char s[maxn];
int vis[30];
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T,n;
scan(T);
while(T--)
{
scanf("%s",s);
scan(n);
mst(vis,0);
int len=strlen(s);
int cnt=0,i=0;
LL ans=0;
for(int j=0;j<len;j++)
{
if(vis[s[j]-'a']==0)
{
vis[s[j]-'a']=1;
cnt++;
}
int flag=0;
if(cnt>=n)
{
ans+=len-j;
i++;
while(s[i]==s[i-1])
{
ans+=len-j;
i++;
}
for(int k=i+1;k<j;k++)
{
if(s[k]==s[i-1])
{
flag=1;
break;
}
}
if(!flag)
{
cnt--;
vis[s[i-1]-'a']=0;
}
else
j--;
}
}
printf("%I64d\n",ans);
}
return 0;
}
看了下别的人代码。。
#include<cstdio>
#include<cstring>
typedef long long ll;
using namespace std;
char str[1000005];
int main()
{
int T,k,t;
ll ans;
scanf("%d",&T);
int vis[30];
int l,r,flag,len;
while(T--)
{
scanf("%s%d",str,&k);
l=r=0;//初始化左右指针
flag=0;
ans=0;
len=strlen(str);
memset(vis,0,sizeof(vis));
while(l<=len-k)
{
while(flag<k&&r<len)
{
t=str[r]-'a';
if(!vis[t])
flag++;//当前已有flag个不同字符
vis[t]++;
r++;
}//寻找以l为起点的最小子串
if(flag==k)
ans+=len-r+1;//包含最小子串的子串都满足条件
t=str[l]-'a';
vis[t]--;
if(!vis[t])
flag--;
l++;//起点右移
}
printf("%lld\n",ans);
}
return 0;
}
C Robot
题解说是卡特兰数或者默慈金数;但是没说是怎么弄出来的,弱也实在没有那个实力能推出这两个数来;两种解法不错的解释:
但还有另一种做法:组合数
定义向左走,向右走,不动分别为操作0,1,2;一共操作n次;问题就转变为在n个位置上放这3个数了,但是要保证以下要求:
1、1的个数和0的个数相等;
2、任意时刻从左到右1的个数要大于等于0的个数
先选i个位置给2,就是
C(n, i)
;剩下n-i个位置,因为0,1个数相等,
那么再在剩下n-i个位置选一半给0(或1),C(n-i, (n-i)/2);剩下的位置就全是1(或0)的了;再减去不符合要求2的情况;枚举所有的 i,就可得出答案
比赛的时候我就是这样想的,但是最后没做出来;因为不知道怎么保证要求2。
后来看了takio巨的ac代码,对于第2个要求,他是这样写的:
C ( n, i) * (C (n - i, (n - i) / 2) - C (n - i, (n - i) / 2 - 1) ) ;
可以这样理解:
先在 n - i 个位置上选 ( n - i) / 2-1 个0,然后把( n - i) / 2个 1 也不管次序插进去,这时候我还有一个0没放,我这个0总有一个放法可以使得你变成不合要求的状态。
ps:我理解这句理解了一下午。。还是没有扑捉到让我完全相信正确的解释。。上面的解释暂时觉得是对的。。我之前以为是这样的解释:
/*
对于这一句。。!!我真的不是想了一般的久。。想了很久很久很久。。3,4小时总是有的。。
我终于明白了!为什么 减去C (n - i, (n - i) /2 - 1) 就把所有不符合的情况排除了;
原来是这样的:
总的来说不符合的可以分为这两种情况:
0 x x x x x 或者
x x x x x 1
即第一步是向左和最后一步是向右(说明你越过原点到负半轴去了);
第一步向左了,顺便后面怎么走都是错,接下来在剩下的n-i-1个位置选出剩下的(n-i)/2-1个0,即C(n-i-1,(n-i)/2-1);
如果你最后一步是向右的,前面怎么走都是错的,在前面n-i-1个位置选出(n-i)/2个0,
即C(n-i-1,(n-i)/2);
两者相加:
C(n-i-1,(n-i)/2-1) + C(n-i-1,(n-i)/2) = C(n-i,(n-i)/2)
被自己的坚持感动了。。。哭。
我终于明白了!为什么 减去C (n - i, (n - i) /2 - 1) 就把所有不符合的情况排除了;
原来是这样的:
总的来说不符合的可以分为这两种情况:
0 x x x x x 或者
x x x x x 1
即第一步是向左和最后一步是向右(说明你越过原点到负半轴去了);
第一步向左了,顺便后面怎么走都是错,接下来在剩下的n-i-1个位置选出剩下的(n-i)/2-1个0,即C(n-i-1,(n-i)/2-1);
如果你最后一步是向右的,前面怎么走都是错的,在前面n-i-1个位置选出(n-i)/2个0,
即C(n-i-1,(n-i)/2);
两者相加:
C(n-i-1,(n-i)/2-1) + C(n-i-1,(n-i)/2) = C(n-i,(n-i)/2)
被自己的坚持感动了。。。哭。
*/
结果没两分钟就被自己推翻了。。
代码:
/* ***********************************************
Author :angon
************************************************ */
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <stack>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
#define REP(i,k,n) for(int i=k;i<n;i++)
#define REPP(i,k,n) for(int i=k;i<=n;i++)
#define scan(d) scanf("%d",&d)
#define scann(n,m) scanf("%d%d",&n,&m)
#define mst(a,k) memset(a,k,sizeof(a));
#define LL long long
#define maxn 2000005
#define mod 1000000007
LL f[maxn],rf[maxn],inv[maxn];
LL C(int n,int m)
{
if(n<0 || m>n) return 0;
return f[n]*rf[m] % mod*rf[n-m] % mod;
}
int main()
{
inv[0]=inv[1]=1;
f[0]=f[1]=rf[0]=rf[1]=1;
for(int i=2;i<=maxn;i++)
{
f[i] = f[i-1]*i % mod;
inv[i] = inv[mod%i]*(mod-mod/i)% mod;
rf[i] = rf[i-1]*inv[i] % mod;
}
int t,n;
scan(t);
while(t--)
{
scan(n);
LL ans=0;
for(int i=n;i>=0;i-=2) //保证了n - i是偶数
{
ans += ( C(n,i) * ( C(n-i,(n-i)/2) - C(n-i,(n-i)/2-1)+ mod ) ) % mod;
}
printf("%I64d\n",ans % mod);
}
return 0;
}
再解释一下37到42行吧;这里用到了逆元的线性求法;如果你还不知道什么是逆元,逆元详解,我见过的最好的逆元博客。
C(n ,m) %M= n ! / m ! / (n-m) ! %M
预处理出 n! % M = f[n] 和 1 / m! %M = rf[m];求rf[]的时候就用到的了逆元