HDU 5671 5672 5673 BestCoder Round #81 (div.1) A B C

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)
被自己的坚持感动了。。。哭。
*/
结果没两分钟就被自己推翻了。。
代码:
/* ***********************************************
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[]的时候就用到的了逆元



你可能感兴趣的:(HDU 5671 5672 5673 BestCoder Round #81 (div.1) A B C)