[2016-3-13 Test]

1. 矩阵问题
(mat.pas/c/cpp)
★问题描述:
对于一个n×n 的01 矩阵,它是合法的仅当它的每行每列有且仅有两个1。并且,如果
一个合法矩阵经过若干次行列变化(即交换两行或交换两列)可以变为另一个合法矩阵,那
么它们就会被认为是相同的。两个3×3 的相同的合法矩阵如下:
1 0 1    |    0 1 1
1 1 0    |    1 0 1
0 1 1    |    1 1 0
★编程任务:
对于给定的n,你需要求出有多少不同的合法矩阵。
★数据输入:
输入文件名为mat.in。
第一行为一个正整数T。
之后T 行每行有一个正整数n。
★结果输出:
输出文件名为mat.out。
对于每组数据输出答案mod 998244353(7×17×223+1,一个质数)。

Input

2 2 3

Output

1 1 1
★数据范围:
10%:T=1,n<=5
50%:T<=10,n<=150
100%:1<=T<=1000,1<=n<=2000。




不知道怎么搞就搞出来了。。

对于一行一列的二元关系QAQ。。

其实我是直接拿一行的两个1做了一个边,发现它是一个size>=2的环。

然后做背包输出就可以了。。




#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define maxn 2010
#define mod 998244353
using namespace std;

void read(int &num){
	num = 0; char ch = getchar();
	for(; ch < '!'; ch = getchar());
	for(; ch > '!'; ch = getchar())
	    num = num * 10 + ch - 48;
}

int dp[maxn];

int main(){
	freopen("mat.in", "r", stdin);
	freopen("mat.out", "w", stdout);
	int test, n = 2000;
	read(test);
	dp[0] = 1;
	for(int i = 2; i <= n; i ++)
		for(int j = i; j <= n; j ++){
            dp[j] += dp[j - i];
            if(dp[j] > mod)dp[j] -= mod;//阿这里没有加等于号QAQ,然而并没有WA。。RP比较好,。,注意!!
		}
		
	while(test --){
		read(n);
		printf("%d\n", dp[n]);
	}
	return 0;
}




2.公共串问题

(str.pas/c/cpp)
★问题描述:
一个给定序列的子序列是在该序列中删去若干元素后得到的序列。确切地说,若给定序
列X= x1 , x2 ,..., xm ,则另一序列Z= z1 , z2 ,..., zk 是X 的子串是指存在一个严格递增下标序
列i1 , i2 ,..., ik 使得对于所有j=1,2,...,k 有z j  xij 。例如,序列Z=GACT 是序列X=GCTACT
的子序列,相应的递增下标序列为1,4,5,6。而当i1 , i2 ,..., ik 满足it 1  it 1 时,序列Z 又被
称为序列X 的子串。例如,序列Z=CTAC 是序列X=GCTACT 的子串,相应的递增下
标序列为2,3,4,5。
★编程任务:
对于给定的两个由小写字母构成的长度不超过2000 的序列A、B,你需要求出:
1、在A 的子串中,不是B 的子串的字符串的数量。
2、在A 的子串中,不是B 的子序列的字符串的数量。
3、在A 的子序列中,不是B 的子串的字符串的数量。
4、在A 的子序列中,不是B 的子序列的字符串的数量。
注:位置不同的相同的子串(序列)只计算一次。
★数据输入:
输入文件名为str.in。
第一行为序列A,第二行为序列B。
★结果输出:
输出文件名为str.out。
输出四行,分别为四个问题的答案mod 998244353(7×17×223+1,一个质数)。

Input
aabbcc 
abcabc 

Output

13

5

20

7



这题TM有毒QAQ。。

HEOI2015

序列自动机,后缀自动机,DP


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define maxn 4010
#define mod 998244353
using namespace std;

struct Node{
	int len, link, nxt[26], s;
	void clear(){
		len = link = s = 0;
		for(int i = 0; i < 26; i ++)
		    nxt[i] = 0;
	}
};

int pre[26];
struct DFN{
	int root, size, last, n;
	Node st[maxn];
	bool vi[maxn];
	void init(){
		for(int i = 0; i <= size; i ++)
		    st[i].clear();
		size = last = root = 0;
		st[root].len = 0;
		st[root].link = -1;
	}

	void Extend(char ch){
		int cur = ++ size, p = last, c = ch - 'a';
		st[cur].len = st[last].len + 1;
		for(; ~p && st[p].nxt[c] == 0; p = st[p].link)
			st[p].nxt[c] = cur;
		if(p == -1)
			st[cur].link = root;
		else{
			int q = st[p].nxt[c];
			if(st[p].len + 1 == st[q].len)
			    st[cur].link = q;
			else{
				int clone = ++ size;
				st[clone] = st[q];
				st[clone].len = st[p].len + 1;
	            for(; ~p && st[p].nxt[c] == q; p = st[p].link)
	                st[p].nxt[c] = clone;
				st[cur].link = st[q].link = clone;
			}
		}last = cur;
	}

	int Go(int now){
		if(vi[now])return st[now].s;
		vi[now] = true;
		int ret = 1;
		for(int i = 0; i < 26; i ++)
			if(st[now].nxt[i]){
				ret += Go(st[now].nxt[i]);
				if(ret >= mod)ret -= mod;
			}
		return st[now].s = ret;
	}

	void buildsam(char* c){
		init();
		n = strlen(c + 1);
		for(int i = 1; i <= n; i ++)
		    Extend(c[i]);

        memset(vi, 0, sizeof vi);
        Go(root);
	}

	void buildseq(char* c){
		init();
		size = strlen(c + 1);
		memset(pre, 0, sizeof pre);
		for(int i = size; i >= 1; i --){
			for(int j = 0; j < 26; j ++)
			    st[i].nxt[j] = pre[j];
			pre[c[i] - 'a'] = i;
		}
		for(int j = 0; j < 26; j ++)
			st[0].nxt[j] = pre[j];
		memset(vi, 0, sizeof vi);
		Go(root);
	}
}A, B;

int DP[maxn][maxn];
bool in[maxn][maxn];
int dp(int art, int brt){
	if(in[art][brt])return DP[art][brt];
    in[art][brt] = true;
	int ret = 0;
	for(int i = 0; i < 26; i ++){
		int child = A.st[art].nxt[i];
        if(child){
			if(B.st[brt].nxt[i])
				ret += dp(child, B.st[brt].nxt[i]);
			else ret += A.st[child].s;
			if(ret >= mod)ret -= mod;
		}
	}
	return DP[art][brt] = ret;
}

char a[maxn], b[maxn];

int main(){
	freopen("str.in", "r", stdin);
	freopen("str.out", "w", stdout);
	scanf("%s%s", a + 1, b + 1);
	A.buildsam(a), B.buildsam(b);
	memset(in, 0, sizeof in);
	printf("%d\n", dp(0, 0));

	A.buildsam(a), B.buildseq(b);
	memset(in, 0, sizeof in);
	printf("%d\n", dp(0, 0));

	A.buildseq(a), B.buildsam(b);
	memset(in, 0, sizeof in);
	printf("%d\n", dp(0, 0));

	A.buildseq(a), B.buildseq(b);
	memset(in, 0, sizeof in);
	printf("%d\n", dp(0, 0));
	return 0;
}

HEOI2015 最短不公共子串

注意要BFS。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define maxn 4010
using namespace std;
const int inf = 0x7fffffff;
int ans;
char s[maxn], c[maxn];
int pre[26];

struct Node{
	int len, link, nxt[26], step;
	void clear(){
		step = len = link = 0;
		for(int i = 0; i < 26; i ++)
		    nxt[i] = 0;
	}
};

struct DFN{
	Node st[maxn];
	int root, size, last;
	bool vis[maxn];
	void init(){
		for(int i = 0; i <= size; i ++)
		    st[i].clear();
		root = size = last = 0;
		st[root].link = -1;
		memset(vis, 0, sizeof vis);
	}
	
	void Extend(char ch){
		int c = ch - 'a', p = last, cur = ++ size;
		st[cur].len = st[p].len + 1;
		for(; ~p && !st[p].nxt[c]; p = st[p].link)
		    st[p].nxt[c] = cur;
		if(p == -1)
		    st[cur].link = root;
		else{
			int q = st[p].nxt[c];
			if(st[q].len == st[p].len + 1)
			    st[cur].link = q;
			else{
				int clone = ++ size;
				st[clone] = st[q];
				st[clone].len = st[p].len + 1;
				for(; ~p && st[p].nxt[c] == q; p = st[p].link)
				    st[p].nxt[c] = clone;
				st[cur].link = st[q].link = clone;
			}
		}last = cur;
	}
	
	
	void buildsam(char* c){
		init();
		int n = strlen(c + 1);
		for(int i = 1; i <= n; i ++)
			Extend(c[i]);
	}
	
	void buildseq(char* c){
		init();
		memset(pre, 0, sizeof pre);
		size = strlen(c + 1);
		for(int i = size; i >= 0; i --){
			for(int j = 0; j < 26; j ++)
			    st[i].nxt[j] = pre[j];
			if(i)pre[c[i] - 'a'] = i;
		}
	}
}A, B;


struct Pair{
	int a, b, l;
	Pair(int x = 0, int y = 0, int z = 0){
		this->a = x;
		this->b = y;
		this->l = z;
	}
};

bool vis[maxn][maxn];
queue<Pair>Q;

int Godp(){
	memset(vis, 0, sizeof vis);
	while(!Q.empty())Q.pop();
	Q.push(Pair(0, 0, 0));
	vis[0][0] = true;
	while(!Q.empty()){
		Pair T = Q.front();Q.pop();
		for(int i = 0; i < 26; i ++){
			int l = A.st[T.a].nxt[i], r = B.st[T.b].nxt[i];
			if(l && !r)return T.l + 1;
			if(vis[l][r])continue;
			if(l && r){
                vis[l][r] = true;
				Q.push(Pair(l, r, T.l + 1));
			}
		}
	}
	return -1;
}

int main(){
	scanf("%s%s", s + 1, c + 1);
	A.buildsam(s), B.buildsam(c);
	printf("%d\n", Godp());
	
	B.buildseq(c);
	printf("%d\n", Godp());
	
	A.buildseq(s), B.buildsam(c);
	printf("%d\n", Godp());
	
	B.buildseq(c);
	printf("%d\n", Godp());
	return 0;
}

3.平均值问题
(seq.pas/c/cpp)
★问题描述:
有n 个数a1,a2,...,an,并给定常数K,K<=10。
接下来有m 个操作。每个操作给定L,R,保证1<=L<=R<=n 且R-L+1>=K。你需要找出
l,r,使得L<=l<=r<=R,r-l+1>=K,且在此基础上区间[l,r]内的平均数最大。如果有多组解, 你需要
找出r-l 最小的;如果仍有多组解,你需要找出l 最小的。找到符合条件的l,r 后,你需要将它
们输出,再把区间[l,r]内的数从序列中删除,并且给序列元素重新从1 开始按顺序
标号。
你的任务即为完成上述操作。
★数据输入:
输入文件名为seq.in。
第一行三个数n,m,K。
第二行n 个正整数a1,a2,...,an。
接下来m 行每行两个正整数L,R。数据保证R 不超过当前序列的长度。
★结果输出:
输出文件名为seq.out。
共m 行,每行两个数代表被删除的区间。
输入示例                                输出示例
10 3 2                                    5 6
5 1 7 2 9 8 3 5 10 8               3 4
1 7                                         1 2
2 5
1 3
★数据范围:
20%:n<=100
40%:n<=1000 100%:1<=n<=100000

orz zcg


(至今未领悟可持久化treap)


#define maxk 20ul
#define maxn 100010ul

#define double_type(h) ((double)(h))

#define pb push_back

#define null NULL
#define ll long long
#define L left
#define R right

#include <vector>
#include <stdio.h>
#include <stdlib.h>

struct node{
	node *left,*right;
	int fix,max_pos,size_;ll sum,max_sum;
	node(ll sum_){
		left=right=null;
		size_=1;
		max_pos=1;
		sum=max_sum=sum_;
		fix=rand();
		return;
	}
	int lsize(){return L!=null?L->size_:0;}
	int rsize(){return R!=null?R->size_:0;}
}*root[maxk];

struct pii{node *x,*y;};
struct prr{int x,y;ll z;};

int n,m,K,K2,seq[maxn];
ll renew,suf[maxn],bs[maxn];
std::vector<ll> que;
const ll inf=1e12;
const double eps=1e-10;

void update(node *p){
	if(p==null) return;
	p->size_=1;
	p->max_pos=p->lsize()+1;
	p->max_sum=p->sum;
	if(p->L!=null&&p->L->max_sum>=p->max_sum){
		p->max_sum=p->L->max_sum;
		p->max_pos=p->L->max_pos;
	}
	if(p->R!=null&&p->R->max_sum> p->max_sum){
		p->max_sum=p->R->max_sum;
		p->max_pos=p->R->max_pos+p->lsize()+1;
	}
	if(p->L!=null) p->size_+=p->L->size_;
	if(p->R!=null) p->size_+=p->R->size_;
	return;
}

void read(int &x){
	x=0;int c=getchar();
	while(c<'0'||c>'9') c=getchar();
	for(;c>='0'&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
	return;
}

void build_tree(node *&rt,int l,int r){
	if(l>r) return;
	int mid=(l+r)>>1;
	rt=new node(bs[mid]);
	build_tree(rt->L,l,mid-1);
	build_tree(rt->R,mid+1,r);
	update(rt);
	return;
}

void build(int k){
	for(int i=1;i<=n;i++){
        if(i>=k) bs[i]=suf[i]-suf[i-k];
		else bs[i]=-inf;
	}
	build_tree(root[k],1,n);
	return;
}

node* merge(node *a,node *b){
	if(a==null) return b;
	if(b==null) return a;
	if(a->fix<b->fix){
		a->R=merge(a->R,b);
		update(a);return a;
	}
	else{
		b->L=merge(a,b->L);
		update(b);return b;
	}
	return null;
}

pii split(node *x,int k){
	if(x==null) return (pii){null,null};
	pii y;
	if(x->lsize()>=k){
		y=split(x->L,k);
		x->L=y.y;update(x);
		y.y=x;
	}
	else{
		y=split(x->R,k-x->lsize()-1);
		x->R=y.x;update(x);
		y.x=x;
	}
	return y;
}

prr query(int k,int l,int r){
	l+=k-1;
	if(l>r) return (prr){0,0,-inf};
	prr ans;
	pii x=split(root[k],r);
	pii y=split(x.x,l-1);
	ans=(prr){y.y->max_pos+l-k,y.y->max_pos+l-1,y.y->max_sum};
	x.x=merge(y.x,y.y);
	root[k]=merge(x.x,x.y);
	return ans;
}

void dfs(node *p){
	if(p==null) return;
	printf("rt->%lld \n",p->sum);
	dfs(p->L),dfs(p->R);
	update(p);
	return;
}

void ud(node *p,int k){
	if(p==null) return;
	if(p->lsize()+1==k){
		p->sum=renew;
		//printf("change %lld ->%lld \n",p->sum,renew);
	}
	else if(p->lsize()>=k) ud(p->L,k);
	else ud(p->R,k-p->lsize()-1);
	update(p);
	return;
}

void recal(int p,int k){
	if(que.size()-1<p) return;
	ll ans=0;
	for(int i=0;i<k;i++){
		if(p-i<0) break;
		ans+=que[p-i];
	}
	renew=ans;
	ud(root[k],p);
	return;
}

void del(int k,int l,int r){
	pii x=split(root[k],r);
	pii y=split(x.x,l-1);
	root[k]=merge(y.x,x.y);
	for(int i=0;i<=k+1;i++) recal(l+i,k);
	return;
}

void work(){
	int L,R,nal,nar;double rt,ans=-inf;
	read(L),read(R);prr tmp;
	for(int i=K;i<K2;i++){
		tmp=query(i,L,R);
		rt=double_type(tmp.z)/double_type(i);
		if(rt-eps>ans) nal=tmp.x,nar=tmp.y,ans=rt;
	}
	printf("%d %d\n",nal,nar);
	que.erase(que.begin()+nal,que.begin()+nar+1);
	for(int i=K;i<K2;i++) del(i,nal,nar);
	return;
}

int main(){
	freopen("seq.in","r",stdin);
	freopen("seq.out","w",stdout);
	srand(19981011);/*good luck*/
	read(n),read(m),read(K),K2=K<<1;
	que.resize(n+1),que[0]=-inf;
	for(int i=1;i<=n;i++){
		read(seq[i]),que[i]=seq[i];
		suf[i]=suf[i-1]+seq[i];
	}
	for(int i=K;i<K2;i++) build(i);
	for(int i=1;i<=m;i++) work();
	return 0;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值