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
3
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;
}
注意要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;
}