BestCoder Round #81 (div.1) A B hdu5571 hdu 5572




链接:戳这里


Matrix 
 Time Limit: 3000/1500 MS (Java/Others)   Memory Limit: 131072/131072 K (Java/Others)
问题描述
有一个nn行mm列的矩阵(1≤n≤1000,1≤m≤1000),在这个矩阵上进行q(1≤q≤100,000) 个操作:

1 x y: 交换矩阵M的第x行和第y行(1≤x,y≤n);
2 x y: 交换矩阵M的第x列和第y列(1≤x,y≤m);
3 x y: 对矩阵M的第x行的每一个数加上y(1≤x≤n,1≤y≤10,000);
4 x y: 对矩阵M的第x列的每一个数加上y(1≤x≤m,1≤y≤10,000);
输入描述
输入包含多组数据. 第一行有一个整数T(1≤T≤15), 表示测试数据的组数. 对于每组数据:
第一行输入3个整数n, m, q.
接下来的nn行,每行包括m个整数,表示矩阵M。(1≤i,j≤10,000),(1≤i≤n,1≤j≤m).
最后qq行,每行输入三个整数a(1≤a≤4), x, y。
输出描述
对于每组数据,输出经过所有q个操作以后的矩阵M。
输入样例
2
3 4 2
1 2 3 4
2 3 4 5
3 4 5 6
1 1 2
3 1 10
2 2 2
1 10
10 1
1 1 2
2 1 2
输出样例
12 13 14 15
1 2 3 4
3 4 5 6
1 10

10 1


思路:cf上有一道类似这样的题,我们用数组H[i],H[j]分别记录当前更换的行i,j的原始行j,i。同理列也是如此

对于当前的行x增加的y值,也直接加到原始的行H[x]上去(列也是一样)

接着N*M处理出 当前的i行j列所对应的值也就是原始的H[i]行L[j]列所对应的值

对应的行列所增加的值也直接增加原始的H[i],L[j]的值

这种类型的题肯定是抓住原始的i,j不放,然后换种方式去更新值


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<iomanip>
#include<cmath>
#define mst(ss,b) memset((ss),(b),sizeof(ss))
#define maxn 0x3f3f3f3f
#define MAX 1000100
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
typedef unsigned long long ull;
#define INF (1ll<<60)-1
using namespace std;
ll a[1010][1010],anw[1010][1010];
int H[1010],L[1010];
ll Hval[1010],Lval[1010];
int n,m,q;
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d%d",&n,&m,&q);
        mst(Hval,0);
        mst(Lval,0);
        mst(anw,0);
        for(int i=1;i<=n;i++) H[i]=i;
        for(int i=1;i<=m;i++) L[i]=i;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                scanf("%I64d",&a[i][j]);
            }
        }
        while(q--){
            int f,x,y;
            scanf("%d%d%d",&f,&x,&y);
            if(f==1) {
                swap(H[x],H[y]);
            } else if(f==2){
                swap(L[x],L[y]);
            } else if(f==3){
                Hval[H[x]]+=y;
            } else {
                Lval[L[x]]+=y;
            }
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                anw[i][j]+=a[H[i]][L[j]];
                anw[i][j]+=Hval[H[i]];
                anw[i][j]+=Lval[L[j]];
            }
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<m;j++){
                printf("%I64d ",anw[i][j]);
            }
            printf("%I64d\n",anw[i][m]);
        }
    }
    return 0;
}
/*
1
2 2 8
1 2
3 4
1 1 2
3 1 5
2 1 2
3 2 4
1 1 2
3 1 5
2 1 2
3 2 4
*/<strong>
</strong>


String 
 Time Limit: 2000/1000 MS (Java/Others)   Memory Limit: 65536/65536 K (Java/Others)
问题描述
有一个 10≤长度≤1,000,000 的字符串,仅由小写字母构成。求有多少个子串,包含有至少k(1≤k≤26)个不同的字母?
输入描述
输入包含多组数据. 第一行有一个整数T(1≤T≤10), 表示测试数据的组数. 对于每组数据:
第一行输入字符串S。
第二行输入一个整数k。
输出描述
对于每组数据,输出符合要求的子串的个数。
输入样例
2
abcabcabca
4
abcabcabcabc
3
输出样例
0
55


思路:

枚举当前的位置i到位置j内有多少不同的之母num

发现i,j的值都是可以线性滚动过去的

也就是找到以区间[i,j]为基础的贡献值(n-j+1)

区间[i,j]表示为以i开头到最近的j内至少有k个不同的字母

然后处理当前的字母s[j]插进来是不是正好使得不同字母达到k个,然后对应的i踢掉一个再判断

具体看代码


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<iomanip>
#include<cmath>
#define mst(ss,b) memset((ss),(b),sizeof(ss))
#define maxn 0x3f3f3f3f
#define MAX 1000100
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
typedef unsigned long long ull;
#define INF (1ll<<60)-1
using namespace std;
string s;
int a[1000100];
int vis[33],num[1000100];
int main(){
    int T,k;
    scanf("%d",&T);
    while(T--){
        mst(num,0);
        mst(vis,0);
        mst(a,0);
        cin>>s;
        scanf("%d",&k);
        int n=s.size();
        for(int i=0;i<n;i++) a[i+1]=s[i]-'a'+1;
        ll ans=0;
        int i=1,j=0,num=0;
        for(i=1;i<=n;i++){
            while(j+1<=n && num<k){
                j++;
                vis[a[j]]++;
                if(vis[a[j]]==1) num++;
            }
            if(num==k){
                ans+=n-j+1;
            }
            vis[a[i]]--;
            if(vis[a[i]]==0) num--;
        }
        printf("%I64d\n",ans);
    }
    return 0;
}<strong>
</strong>


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值