2020-06 CSP真题
1. 线性分类器
- 线性分类器
- 思路:
#include<bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define per(i, a, b) for(int i = (a); i >= (b); i--)
#define ll long long
#define db double
#define VI vector<int>
#define PII pair<int, int>
const db Pi = 3.141592653589793;
const int INF = 0x7fffffff;
const int N = 1e3 + 5;
const db eps = 1e-10;
int n, m, x[N], y[N], Alow, Blow, Ahigh, Bhigh, a, b, c;
char type[N];
bool check(int x0, int y0){
if(c == 0){
if(b * x0 + a < 0) return 0;
else return 1;
}
else{
if(-1 * (a + b * x0) > c * y0) return 0;
else return 1;
}
}
int main(){
cin >> n >> m;
rep(i, 1, n) cin >> x[i] >> y[i] >> type[i];
rep(j, 1, m){
cin >> a >> b >> c;
Alow = Blow = Ahigh = Bhigh = 0;
rep(i, 1, n){
if(check(x[i], y[i])) type[i] == 'A' ? Ahigh++ : Bhigh++;
else type[i] == 'A' ? Alow++ : Blow++;
}
if((Ahigh == 0 && Blow == 0) || (Alow == 0 && Bhigh == 0)) puts("Yes");
else puts("No");
}
}
2. 稀疏向量
- 稀疏向量
- 思路:
#include<bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define per(i, a, b) for(int i = (a); i >= (b); i--)
#define ll long long
#define db double
#define VI vector<int>
#define PII pair<int, int>
const db Pi = 3.141592653589793;
const int INF = 0x7fffffff;
const int N = 1e5 + 5;
const db eps = 1e-10;
int n, A, B, num, val;
ll sum;
map<int, ll> amp, bmp;
set<int> ast, bst, inter;
set<int>::iterator iter;
int main(){
cin >> n >> A >> B;
rep(i, 1, A){
cin >> num >> val;
amp.insert({num, val});
ast.insert(num);
}
rep(i, 1, B){
cin >> num >> val;
bmp.insert({num, val});
bst.insert(num);
}
set_intersection(ast.begin(), ast.end(), bst.begin(), bst.end(), inserter(inter, inter.begin()));
sum = 0;
for(iter = inter.begin(); iter != inter.end(); iter++){
sum += amp[*iter] * bmp[*iter];
}
cout << sum << endl;
}
3. Markdown渲染器
//会者不难,难者不会。好复杂,但是懂了就懂了
#include<bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define per(i, a, b) for(int i = (a); i >= (b); i--)
#define ll long long
#define PSI pair<string, int>
const int N = 1e5 + 5;
int w, lastspace = 0; //lastspace表示上一个 s 是否为空行
string s;
ll ans;
vector<PSI> store; //分为三类: 1 表示段落, 2 表示项目列表首项目, 3 表示项目列表非首项目
bool isspace(string str){
rep(i, 0, (int)str.length() - 1) //注意length()返回值不是int类型,是size_t类型,需要转换!!!
if(str[i] != ' ') return 0;
return 1;
}
string delete_space(string s){ //删除开头结尾的空格
int l = 0, r = s.size() - 1;
while(s[l] == ' ') l++;
while(s[r] == ' ') r--;
return s.substr(l, r - l + 1);
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin >> w;
//预处理
while(getline(cin, s)){ //处理第一个带内容行.因为没有上一行,不能判断
if(isspace(s)) continue;
if(s[0] == '*' && s[1] == ' ') store.push_back({delete_space(s.substr(2)), 2});
else store.push_back({delete_space(s), 1});
break;
}
lastspace = 0;
while(getline(cin, s)){
if(isspace(s)){
lastspace = 1;
continue;
}
if(lastspace == 1){ //上一行为空行
if(s[0] == '*' && s[1] == ' ') //项目列表首项目首行
store.push_back({delete_space(s.substr(2)), 2});
else //段落
store.push_back({delete_space(s), 1});
}
else{ //上一行非空行
PSI &Last = store.back(); //引用可直接加
if(Last.second != 1){ //在项目列表中
if(s[0] == '*' && s[1] == ' ') //此行为项目列表非首项目的首行
store.push_back({delete_space(s.substr(2)), 3});
else if(s.length() >= 2 && s.substr(0, 2) == " ") //此行为项目列表的项目中的非首行
Last.first += (" " + delete_space(s.substr(2))); //此时有可能上一行项目首行为空白,则此行加入不应加空格。此判断在最后统计时考虑,这里不做讨论
else //此行为段落
store.push_back({delete_space(s), 1});
}
else{ //在段落中
if(s[0] == '*' && s[1] == ' ') //此行为项目列表首项目的首行
store.push_back({delete_space(s.substr(2)), 2});
else //此行均视为段落
Last.first += " " + delete_space(s);
}
}
lastspace = 0;
}
//渲染
ans = 0;
rep(i, 0, (int)store.size() - 1){
PSI &now = store[i];
string str = now.first;
if(i > 0 && now.second != 3) ans++;
int nowwide = w - (now.second == 1 ? 0 : 3); //根据段落和项目区分终端宽度
if(str == ""){ //空白行列表也算一行,细节
ans++;
continue;
}
for(int i = 0; i < str.size(); i += nowwide){
while(str[i] == ' ' && i < str.length()) i++;
ans++;
}
}
cout << ans << endl;
}
4. 1246(digits)
-
转移方程:
i − 1 i-1 i−1 4,64 1,16 i i i 1 2 4 6 16 26 41 42 44 46 61 62 64 66
//回溯 + 矩阵快速幂dp
#include<bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define per(i, a, b) for(int i = (a); i >= (b); i--)
#define ll long long
#define PSI pair<string, int>
const int N = 1e2 + 5;
const ll mod = 998244353;
int n, cnt;
ll k, res = 0;
string s;
struct AC{
ll m[N][N];
}mi, E, power, powertmp;
string formap[N] = {"x", "1", "2", "4", "6", "16", "26", "41", "42", "44", "46", "61", "62", "64", "66"};
map<string, int> mp;
map<string, string> mpp;
PSI pr[N];
void Set(int y, int x){
power.m[x][y] = 1;
}
AC mul(AC x, AC y){
AC c;
rep(i, 1, n) rep(j, 1 ,n) c.m[i][j] = 0;
rep(i, 1, n) rep(j, 1 ,n){
rep(k, 1, n){
c.m[i][j] += x.m[i][k] * y.m[k][j] % mod;
c.m[i][j] %= mod;
}
}
return c;
}
int pow(AC power, ll k, int id){
AC c = E;
while(k > 0){
if(k % 2 == 1) c = mul(c, power);
power = mul(power, power);
k >>= 1;
}
// rep(i, 1, 14){
// rep(j, 1, 14) cout << c.m[i][j] << " ";
// cout << endl;
// }
return c.m[2][id] % mod;
}
inline void init(){
//设置矩阵大小
n = 14, cnt = 0;
//离散化
rep(i, 1, n) mp[formap[i]] = i;
//转移矩阵,用作矩阵快速幂
/* 14 x 14:
0 1 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0 0 0 0
1 0 0 1 1 0 0 0 0 0 0 0 0 0
0 0 1 1 0 0 0 0 0 0 0 0 1 0
0 0 0 0 0 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0 0 0 0
*/
Set(mp["1"], mp["4"]);
Set(mp["2"], mp["1"]);
Set(mp["4"], mp["2"]), Set(mp["4"], mp["6"]);
Set(mp["6"], mp["4"]), Set(mp["6"], mp["6"]);
Set(mp["16"], mp["4"]);
Set(mp["26"], mp["16"]);
Set(mp["41"], mp["64"]);
Set(mp["42"], mp["61"]);
Set(mp["44"], mp["62"]);
Set(mp["46"], mp["26"]), Set(mp["46"], mp["66"]);
Set(mp["61"], mp["44"]);
Set(mp["62"], mp["41"]);
Set(mp["64"], mp["6"]), Set(mp["64"], mp["42"]);
Set(mp["66"], mp["46"]);
//构造单位矩阵E
rep(i, 1, n) rep(j, 1, n) E.m[i][j] = (i == j ? 1 : 0);
}
string PER(string s){
int v = 0;
string tmp = "";
while(v < s.length()){
// cout << s[v] << " " << s[v + 1] << endl;
if(s[v] == '1'){
if(s[v + 1] == '6' || v + 1 >= s.length()) tmp += "4", v += 2;
else return "0";
}
else if(s[v] == '2') tmp += "1", v += 1;
else if(s[v] == '4') tmp += "2", v += 1;
else if(s[v] == '6'){
if(s[v + 1] == '4' || v + 1 >= s.length()) tmp += "6", v += 2;
else return "0";
}
}
return tmp;
}
void dfs(string s, int len){
if(s.length() <= 2){
rep(i, 1, 14)
if(s == formap[i]){
pr[++cnt] = {s, k - len};
return;
}
return;
}
//开头第一个数字决定分支
if(s[0] == '1'){//"4" --> "1(6)"
if(s[1] == '6') dfs("4" + PER(s.substr(2, s.length() - 2)), len + 1);
}
else if(s[0] == '2'){//"1" --> "2"
dfs("1" + PER(s.substr(1, s.length() - 1)), len + 1);
}
else if(s[0] == '4'){//"2" --> "4" & "6" --> "(6)4"
dfs("2" + PER(s.substr(1, s.length() - 1)), len + 1);
dfs("6" + PER(s.substr(1, s.length() - 1)), len + 1);
}
else if(s[0] == '6'){//"6" --> "6(4)" & "4" --> "(1)6"
if(s[1] == '4') dfs("6" + PER(s.substr(2, s.length() - 2)), len + 1);
dfs("4" + PER(s.substr(1, s.length() - 1)), len + 1);
}
return;
}
int main(){
cin >> k >> s;
init();
//处理|s|>2 的情况
dfs(s, 0);
rep(i, 1, cnt){
powertmp = power; //pow 操作修改了powertmp所以
res += pow(powertmp, pr[i].second - 1, mp[pr[i].first]);
res %= mod;
}
cout << res;
}