Codeforces #299 div1
2015-06-10 17:06:06
【传送门】
总结:挺久以前开的 vp,正赛没做。。
A题:数学、二分
题意:给出一个序列 A,A+B,A+2B,...,A+nB
每次询问会给出 l,t,m,意思是从序列中选取一段 A+(l-1)B,...,A + (r-1)B,每次你可以选择不同的最多 m 个数使他们都减1,最多执行 t 次,问最大的 r 值为多少。
思路:比较明显的二分答案,但是检查的步骤呢?
需要考虑两点:(1)序列的最大值不能超过 t,这个比较显然。
(2)序列的和不能超过 m×t
神奇的是只用考虑以上两点即可。
简证:(1)如果序列个数小于等于m,显然正确。
(2)序列个数大于 m,每次取 m 个最大的数让他们减1,最后肯定会剩一堆很小的数,由于 t 大于等于最大值,所以最后必定能减完。
官方的Tutorial给的是一种类似数学归纳法
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <vector> #include <map> #include <set> #include <stack> #include <queue> #include <string> #include <iostream> #include <algorithm> using namespace std; #define MEM(a,b) memset(a,b,sizeof(a)) #define REP(i,n) for(int i=0;i<(n);++i) #define FOR(i,a,b) for(int i=(a);i<=(b);++i) #define getmid(l,r) ((l) + ((r) - (l)) / 2) #define MP(a,b) make_pair(a,b) typedef long long ll; typedef pair<int,int> pii; const int INF = (1 << 30) - 1; int A,B,n; int l,t,m; ll st; bool Check(ll r){ //l -> r ll R = (ll)A + (ll)(r - 1) * B; if(t < R) return false; if((st + R) * (r - l + 1) / 2 > (ll)t * m) return false; return true; } int main(){ scanf("%d%d%d",&A,&B,&n); REP(i,n){ scanf("%d%d%d",&l,&t,&m); st = (ll)A + (ll)(l - 1) * B; ll sum = (ll)t * m; ll top = l + sum / A; ll L = l,R = top; while(L < R){ ll mid = getmid(L,R); if(Check(mid)) L = mid + 1; else R = mid; } if(L <= l) printf("-1\n"); else printf("%I64d\n",L - 1); } return 0; }
B题:扩展KMP
题意:给出一个子串,和若干个其在大串中的匹配起点,问你有多少种符合条件的大串。如果不存在这种大串,输出-1
思路:从小到大逐对考虑匹配起点,如果两个点的差距 >= 子串的长度,那么 distance - length 个位置的字母是26个字母随便放的,26的幂可以用快速幂。
如果两个点的距离 < 子串的长度,那么就要考虑两个子串重叠部分是否一致,这就是后缀是否匹配前缀的问题了,可以用拓展KMP解决。
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <vector> #include <map> #include <set> #include <stack> #include <queue> #include <string> #include <iostream> #include <algorithm> using namespace std; #define MEM(a,b) memset(a,b,sizeof(a)) #define REP(i,n) for(int i=0;i<(n);++i) #define FOR(i,a,b) for(int i=(a);i<=(b);++i) typedef long long ll; const int MAXN = 1000010; const ll mod = 1e9 + 7; int n,m; char s[MAXN]; int y[MAXN]; int len; int nxt[MAXN]; void Ex_kmp(){ int k = 0,j,p,L; nxt[0] = len; while(k < len - 1 && s[k + 1] == s[k]) k++; nxt[1] = k; k = 1; for(int i = 2; i < len; ++i){ p = k + nxt[k] - 1,L = nxt[i - k]; if(i + L > p){ j = p - i + 1; if(j < 0) j = 0; while(i + j < len && s[i + j] == s[j]) j++; nxt[k = i] = j; } else nxt[i] = L; } } ll Q_pow(int v){ ll res = 1,x = 26LL; while(v){ if(v & 1) res = res * x % mod; x = x * x % mod; v >>= 1; } return res; } int main(){ scanf("%d%d",&n,&m); scanf("%s",s); len = strlen(s); Ex_kmp(); REP(i,m) scanf("%d",&y[i]); if(y[m - 1] + len - 1 > n){ printf("0\n"); return 0; } ll ans = m == 0 ? Q_pow(n) : Q_pow(y[0] - 1) * Q_pow(n - y[m - 1] - len + 1) % mod; FOR(i,1,m - 1){ int d = y[i] - y[i - 1]; if(d >= len) ans = ans * Q_pow(d - len) % mod; else if(nxt[d] < len - d){ ans = 0; break; } } printf("%I64d\n",ans); return 0; }