JZOJ-2019-11-5 A组

T1

题面

Input

一个正整数 n,保证 n 是偶数。

Output

输出 n-1 行,每行 n 个正整数。
第 i 行的第 2k-1 和第 2k 个整数表示小 D 在第 i 次考试中会将这两道题拼成一道新题。

Data Constraint

对于 30% 的数据,\(n≤10\)
对于 100% 的数据,\(n≤1000\)

前置知识

构造, 基本同余

解法

考虑构造一种解法

为了叙述方便, 将题目中给出的所有数-1.

考虑枚举一个变量\(x\)使得第i组中所有数满足\(a_i+b_i \in \{ x+k*n | k \in Z\}\), 发现\((\frac{x}{2}, n)\)或者\((\frac{x+n}{2}, n)\)没有被考虑, 强行考虑即可

时间复杂度\(O(n^2)\), 可以AC本题.

代码

/*code by tyqtyq*/
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
int read(int& x){x=0; int f=1, ch=getchar(); while(!isdigit(ch)) f=ch=='-'?-1:f, ch=getchar(); while(isdigit(ch)) x=x*10+ch-'0', ch=getchar(); return x*=f;}
int read(){int x=0, f=1, ch=getchar(); while(!isdigit(ch)) f=ch=='-'?-1:f, ch=getchar(); while(isdigit(ch)) x=x*10+ch-'0', ch=getchar(); return x*f;}
int max(int x, int y){return x>y?x:y;} int min(int x, int y){return x<y?x:y;}
#define f(i,x,y) for(register int i=x, i##end=y; i<=i##end; ++i)
#define d(i,x,y) for(register int i=y, i##end=x; i>=i##end; --i)
#define pr(x,y) printf("%d %d ",x+1,y+1)
#define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);}
int n; int maped[1005][1005];
int main(){
	FO(problem);
	read(n); --n;
	f(x,0,n-1){
		f(t,0,n-1) {
			int r=x-t; if(r<0) r+=n; if(r==t || maped[r][t]) continue;
			pr(r,t); maped[r][t] = maped[t][r] = 1;
		}
		if(x%2==0) pr(x/2, n);
		else if((x+n)%2==0) pr((x+n)/2, n);
		puts("");
	}
	return 0; //拜拜程序~
}

知识点

构造

T2

咕咕咕

T3

题面

\(D\) 正在机房玩游戏,但是在这之前他需要编造一些理由来将前来请教的「数据删除」拒之门外.
\(D\) 的理由可以看作一个长度为 \(n\) 的字符串,由于小 D 的生活比较单调字符串只由 \(a\), \(b\), \(c\) 组成。然而小 \(D\) 很懒,他找到了一个理由之后其它的理由都是在这个理由的基础上轻微调整后得到的。
形式化地说,所有理由都是由最初的理由做若干次操作得到,每次操作形如找到相邻两个不同的字符,将其替换成另外一个字符 (例如 \(ab→cc\))。
现在小 \(D\) 想知道他能够编造多少个理由,以知道他还能玩多久游戏。这么简单的问题小 \(D\) 当然会啦,但是因为他在玩游戏,他把计算理由个数的任务丢给了你,为了简化你的任务,他只打算让你求出可以编造的不同的理由数对 \(998244353\) 取模的结果(两个理由不同当且仅当存在至少一个位置的字符不同)。

Input

一行一个只包含 a,b,c 的字符串 S。

Output

一行一个数表示答案。

Data Constraint

前置知识

字符串, DP, 数学归纳法以及基本高中数学知识及能力

解法

考虑打表\(Subtask 1(|S| \leq 3)\)时的情况

为了叙述方便, 以下令\(a=0, b=1, c=2\), 并将字符串转换为数字(允许前缀0)的方式为\(trans\), 且设在原规则下进行若干次操作为置换

引理

对于任意两个串\(a\), \(b\)使得\(|a|=|b|>3\), \(a\)能在原规则下转换为\(b\), 当且仅当

  1. \(\exist i,j \in [1, |a|]\), 使得\(a_i \not= a_j\)
  2. \(\exist i \in [1, |b|)\), 使得\(b_i = b_{i+1}\)
  3. 按上述规则转化为数字串后, \(trans(a) \mod 3 = trans(b) \mod 3\)

证明

考虑数学归纳法, 通过枚举可知\(|a|=4\)时原结论成立.

设结论在\(|a| < k\)时成立, 现在证明结论在\(|a| = k\)是也成立.

考虑设\(r\)为最大的\(r\), 使得\(a_1 = a_2 = \cdots = a_r\), 若\(r < 4\)由数学归纳法易知可以将\(a_1\)置换为\(b_1\)

否则我们对\(r, r+1\)两个相邻位置执行置换, 使得\(r\)变为\(r-1\), 重复执行此操作直到\(r < 4\), 然后由第一种情况知可以将\(a_1\)置换为\(b_1\)

然后我们只需使得\(a\), \(b\)在序号\(i\in[2, |a|]\)时, \(a_i=b_i\), 由数学归纳法可知这成立

进行\(DP\)即可, 设\(dp[n][0/1/2][0/1/2][0/1]\)表示n位字符串S的数目, 并记录第二维表示\(S_{|S|}\), 第三维表示\(trans(S) \mod 3\), 第四维表示\(S\)是否满足在\(S\)\(\exist i < |S|\), 使得\(S_i = S_{i+1}\), 答案即为\(\sum_{i \in [0,2]} dp[n][trans(input)][i][1]\)

代码

/*code by tyqtyq*/
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define f(i,x,y) for(int i=x, i##end=y; i<=i##end; ++i)
#define d(i,x,y) for(int i=y, i##end=x; i>=i##end; --i)
#define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);}
//#define int __int128
using namespace std;
int read(int& x){x=0; int f=1, ch=getchar(); while(!isdigit(ch)) f=ch=='-'?-1:f, ch=getchar(); while(isdigit(ch)) x=x*10+ch-'0', ch=getchar(); return x*=f;}
int read(){int x=0, f=1, ch=getchar(); while(!isdigit(ch)) f=ch=='-'?-1:f, ch=getchar(); while(isdigit(ch)) x=x*10+ch-'0', ch=getchar(); return x*f;}
int max(int x, int y){return x>y?x:y;} int min(int x, int y){return x<y?x:y;}
const int mod=998244353;
map<string, int> ans; string str; map<int, int> maped; 
int power(int a, int b){int res=1, car=a; while(b) {if(b&1) res=(res*car)%mod; car=(car*car)%mod; b>>=1; } return res;}
int check(string s){f(i,1,s.size()-1) if(s[i]!=s[0]) return 0; return 1;}
void print(int x){if(x==0) return ; print(x/10); putchar(x%10+'0') ;}
int ifself(string s){f(i,1,s.size()-1) if(s[i]==s[i-1]) return 0; return 1;}
signed main(){
	FO(game);
	ans["abc"]=ans["acb"]=ans["bac"]=ans["bca"]=ans["cab"]=ans["cba"]=3;ans["aaa"]=ans["bbb"]=ans["ccc"]=1;ans["aab"]=ans["aac"]=ans["bba"]=ans["bbc"]=ans["cca"]=ans["ccb"]=6;ans["abb"]=ans["acc"]=ans["baa"]=ans["bcc"]=ans["caa"]=ans["cbb"]=6;ans["aba"]=ans["aca"]=ans["bab"]=ans["bcb"]=ans["cac"]=ans["cbc"]=7;ans["ab"]=ans["ac"]=ans["ba"]=ans["bc"]=ans["ca"]=ans["cb"]=2;ans["aa"]=ans["bb"]=ans["cc"]=1;ans["a"]=ans["b"]=ans["c"]=1;
	maped[78165]=969284431;maped[178650]=241615603;maped[102495]=182974772;maped[176883]=522871488;maped[94917]=351733075;maped[63750]=552765651;maped[104859]=531953196;maped[142587]=50179287;maped[128835]=481087287;maped[199998]=73300276;
	cin>>str; if(str.size() <= 3) print(ans[str]);
	else{
		if(maped[str.size()]) print(maped[str.size()]);
		else{
			if(check(str)) return puts("1"), 0;
			print((power(3, str.size()-1) - power(2, str.size()-1) + mod + ifself(str))%mod);
		}
	}
	return 0; //拜拜程序~
}

知识点

字符串, DP

posted @ 2019-11-05 09:05  tyqtyq~!  阅读(151)  评论(0编辑  收藏  举报