SXOI2016 部分解题报告
来源:互联网 发布:centos查看php版本 编辑:程序博客网 时间:2024/05/22 06:38
第四题还没做…先贴前三个题的。
T1 bridge
Description
有一支
Input
- 第一行为两个正整数
W,n - 接下来
n 行每行两个数ti,wi 。
Output
- 仅一个数,为最小花费时间。
Sample
Input
100 324 6010 4018 50
Output
42
Hint
- 对于40%的数据,
n≤8 - 对于70%的数据,
n≤12 - 对于100%的数据,
n≤16,100≤W≤400,1≤t≤50,10≤w≤100
Solution
数据范围告诉我们应该考虑状压dp。
用
T(A),W(A)分别表示通过的时间最大值和重量总和。
现在问题转化为如何枚举集合的子集。如果用朴素的枚举只能拿到70分左右。从《挑战程序设计竞赛》上学到的一个方法则可以降低复杂度:
sub = S; do { //... sub = (sub-1)&S; } while (sub > 1)
这样处理sub就枚举了
总的复杂度可以用:
打个表就知道能O(能过)…
#include <bits/stdc++.h>using namespace std;int dp[1<<18], W, n;int w[20], t[20];int A[1<<18], M[1<<18];int dfs(int S){ if (S == 1) return 0; if (dp[S] != -1) return dp[S]; dp[S] = 1e6; int sap = S; do { int ans = A[sap], mx = M[sap]; if (ans <= W) dp[S] = min(dp[S], dfs(S^sap)+mx); sap = S&(sap-1); } while (sap > 1); //cout << S << " --> " << dp[S] << endl; return dp[S];}int main(){ freopen("bridge.in", "r", stdin); freopen("bridge.out", "w", stdout); memset(dp, -1, sizeof dp); scanf("%d%d", &W, &n); for (int i = 1; i <= n; i++) scanf("%d%d", &t[i], &w[i]); int S0 = (1<<(n+1))-1; for (int i = 2; i <= S0; i++) { for (int j = 1; j <= n; j++) if (i&(1<<j)) A[i] += w[j], M[i] = max(M[i], t[j]); } cout << dfs(S0) << endl; return 0;}
T2 sequence
Description
定义
而
对于给定的
Input
- 一个数n
Output
- 一个数
Gnmod109+7 。
Sample
Input
3
Output
5
Hint
- 对于30%的数据,
n≤20 - 对于50%的数据,
n≤5000 - 对于70%的数据,
n≤107 - 对于100%的数据,
n≤1018
Solution
首先看样例解释很容易发现一个递推式:
打表找规律会发现
因此:
原命题得证。然后只需要矩阵
做快速幂取模就好了。注意特判。
#include <bits/stdc++.h>using namespace std;struct Matrix { long long a[3][3]; Matrix() { memset(a, 0, sizeof a); } friend Matrix operator * (const Matrix &a, const Matrix &b) { Matrix C; for (int i = 1; i <= 2; i++) for (int j = 1; j <= 2; j++) for (int k = 1; k <= 2; k++) (C.a[i][j] += a.a[i][k] * b.a[k][j]) %= 1000000007; return C; }};Matrix I(){ Matrix C; memset(C.a, 0, sizeof C.a); C.a[1][1] = C.a[2][2] = 1; return C;}Matrix power(const Matrix &a, long long n){ if (n == 0) return I(); Matrix p = power(a, n>>1); p = p*p; if (n&1) p = p*a; return p;}int main(){ freopen("sequence.in", "r", stdin); freopen("sequence.out", "w", stdout); long long n; cin >> n; if (n == 0) {cout << 1 << endl; return 0;} if (n == 1) {cout << 1 << endl; return 0;} Matrix M; M.a[1][1] = 2, M.a[1][2] = 1, M.a[2][1] = 1; M = power(M, n-1); cout << M.a[1][1] << endl; return 0;}
T3 string
Description
给定
Input
- 第一行一个整数
n - 接下来
n 行,每行先是一个整数w ,表示这个字符串的长度;然后是一个空格;之后给出这个长度为w 的字符串。保证w≠0 。
Output
- 仅一个正整数,表示有序对的个数。
Sample
Input
72 aa3 aba3 aaa6 abaaba5 aaaaa4 abba
Output
14
Hint
- 14个有序对中,6个为
(i,i) ,其他8个分别为: (1,3),(1,5),(3,5),(2,6),(3,1),(5,1),(5,3),(6,2) m 为总字符数。- 对于20%的数据,
n≤100,m≤500 - 对于40%的数据,
n≤5000,m≤2000000 - 对于100%的数据,
n≤2000000,m≤2000000
Solution
当时考场上sdf一个女选手怒而碾过Orz……
我们用
考虑两个回文串
满足题目中条件为:
按照穿脱原则展开:
也就是:
所以原问题转化为了求
移项并整理,得到:
可以看到两侧都变成了只含有一个量的表达式,成功地将两个量的关系转化成了一个量的性质,除法可以用模大素数下的乘法逆元处理,因此就可以丢进hash算了。
然而一个问题是这样做冲突严重。如果懒得写拉链怎么办呢?一个有趣的方法是考虑
至于base的选取..亲测37效果最好…不知道为什么,可能是数据的缘故吧…
#include <bits/stdc++.h>using namespace std;long long mod = 2016122203ll, base = 37;long long power(long long a, long long n){ if (n == 0) return 1; long long p = power(a, n>>1); (p *= p) %= mod; if (n&1) (p *= a) %= mod; return p;}long long inv(long long a){ return power(a, mod-2); }long long hash_val(char str[]){ long long ans = 0; for (char *p = str; *p != '\0'; ++p) ((ans *= base) += (*p-'a'+1)) %= mod; return ans;}map<long long, int> hash_set;int n, w;char str[2000005];long long cnt = 0;inline int read() { int a = 0, c; do c = getchar(); while(!isdigit(c)); while (isdigit(c)) { a = a*10+c-'0'; c = getchar(); } return a;}inline void read(char str[]){ char c; int i = 0; do c = getchar(); while(!isalpha(c)); while (isalpha(c)) { str[i++] = c; c = getchar(); } str[i] = '\0';}int main(){ freopen("string.in", "r", stdin); freopen("string.out", "w", stdout); scanf("%d", &n); for (int i = 1; i <= n; i++) { w = read(); read(str); long long val = inv(((power(base, w)-1)+mod)%mod); (val *= hash_val(str)) %= mod; cnt += hash_set[val*str[w-1]]; hash_set[val*str[w-1]]++; } cout << cnt*2+n << endl; return 0;}
- SXOI2016 部分解题报告
- 2011多校九部分解题报告
- noi2017解题报告(部分)
- Regionals 2011, Asia - Dhaka 部分解题报告
- 训练指南第一部分解题报告
- 第三部分:POJ 1000 解题报告
- 第三部分:POJ 1003 解题报告
- 第三部分:POJ 1005 解题报告
- 第三部分:POJ 1007 解题报告
- 第三部分:POJ 1006 解题报告
- SXOI2016 期末考试
- hdu 1913 computer 部分贪心+一维dp 解题报告
- 2011多校联合五部分解题报告
- 大连赛区网络赛部分题目解题报告
- Codeforces Round #181 (Div. 2) 部分解题报告
- 第六届蓝桥杯2015本科B组c/++部分解题报告
- 某【并不能AC的】模拟题部分解题报告
- 山西NOIp四校联考部分解题报告
- leetcode [Balanced Binary Tree]//待整理多种解法
- POJ1611 The Suspects 并查集
- 模拟实现atoi函数
- JAVA输入输出流(IO)
- Short-Time Fourier Transform
- SXOI2016 部分解题报告
- Java与C++的差异(1)
- 异常处理——异常函数之SetUnhandledExceptionFilter(子进程处理)(3)
- 4. Median of Two Sorted Arrays
- 5-13 是否完全二叉搜索树 (30分)
- coder初入职场必备:Eclipse+Tomcat8+MAVEN+SVN 工作环境搭建
- Android Device Monitor 文件管理的常见问题
- Canvas学习
- java观察者模式不一样的使用