d p [ i ] = ( d p [ i + A ] + d p [ i + A + 1 ] + . . . + d p [ i + B ] ) / ( B − A + 1 ) + 1 dp[i]=(dp[i+A]+dp[i+A+1]+...+dp[i+B])/(B-A+1)+1 dp[i]=(dp[i+A]+dp[i+A+1]+...+dp[i+B])/(B−A+1)+1
要留意一下当 A = 0 A=0 A=0 时候的特判: d p [ i ] = ( d p [ i + A + 1 ] + . . . + d p [ i + B ] + B − A + 1 ) / ( B − A ) dp[i]= (dp[i+A+1]+...+dp[i+B]+B-A+1)/(B-A) dp[i]=(dp[i+A+1]+...+dp[i+B]+B−A+1)/(B−A)
#include<bits/stdc++.h>usingnamespace std;typedeflonglong ll;constint N =2e6+10;constint INF =0x3f3f3f3f;double dp[N]={
0};int n, A, B;intmain(){
scanf("%d %d %d",&n,&A,&B);if(A ==0){
double sum =0;for(int i = n -1; i >=0;--i){
sum -= dp[i + B +1];
sum += dp[i +1];
dp[i]=(sum + B - A +1)/(B - A);}printf("%.10lf\n", dp[0]);}else{
double sum =0;for(int i = n -1; i >=0;--i){
sum -= dp[i + B +1];
sum += dp[i + A];
dp[i]= sum /(B - A +1)+1.0;}printf("%.10lf\n", dp[0]);}return0;}
B. Battleship
签到题。根据题意将10 * 10的矩阵依次用元素覆盖,若覆盖出现重叠则输出 N N N,否则输出 Y Y Y
直接无脑暴力即可
#include<bits/stdc++.h>usingnamespace std;typedeflonglong ll;constint N =1e6+10;constint NN =1e2+10;constint INF =0x3f3f3f3f;int n;bool mp[NN][NN];boolcheck(int x,int y){
if(x <1|| x >10|| y <1|| y >10)returnfalse;returntrue;}intmain(){
scanf("%d",&n);bool flag =true;for(int i =1; i <= n;++i){
int x, y;int l, op;scanf("%d%d%d%d",&op,&l,&x,&y);if(op ==0)for(int j = y; j <= y + l -1;++j){
if(!check(x, j)|| mp[x][j])
flag =false;
mp[x][j]=true;}elsefor(int j = x; j <= x + l -1;++j){
if(!check(j, y)|| mp[j][y])
flag =false;
mp[j][y]=true;}}if(flag)puts("Y");elseputs("N");return0;}
C. Concatenating Teams
根据题目意思,对于在 A A A 中的字符串 a i , a j a_i,a_j ai,aj 以及一个字符串 s s s ,满足 a i = a j + s a_i=a_j+s ai=aj+s
同样在 B B B 中的字符串 b i , b j b_i,b_j bi,bj 以及一个字符串 c c c ,满足 b i = b j + c b_i=b_j+c bi=bj+c
那么当 s = c s=c s=c 的时候,就会多次构成相同的字符串
利用这一个特性,找到所有 A A A 中的 s s s 以及 B B B 中的 c c c ,对于 s = c s=c s=c 的所有串而言,把这个串排除在答案外就可以了。
可以暴力的用 h a s h hash hash 并进行空间换取时间,也可以使用前缀树与后缀树做
如下代码是暴力 h a s h hash hash ,time:1855ms
#include<bits/stdc++.h>
using namespace std;typedeflonglong ll;typedefunsignedlonglong ull;typedef pair<ull, ull> pii;typedef pair<ll, ll>pll;
template<typename T>inlinevoidrd(T& x){
int tmp =1;char c =getchar(); x =0;while(c >'9'|| c <'0'){
if(c =='-')tmp =-1; c =getchar();}while(c >='0'&& c <='9'){
x = x *10+ c -'0'; c =getchar();}
x *= tmp;}constint N =1e5+10;constint M =1e7+10;constint mod =1e9+7;const ull seed =31;const ll NUM =5782344;
ll gcd(ll x, ll y){
if(y ==0)return x;returngcd(y, x % y);}int n, m;inline bool cmp(const string& a,const string& b){
return a.size()< b.size();}
unordered_map<ull, bool>hash_A, hash_B;
unordered_map<ull, bool>pref, suff;
ull prefHash(string s,int st,int ed){
ull ans =0;for(int i = st; i < ed;++i){
ans = ans * seed + s[i]-'a'+1;}return ans;}
ull suffHash(string s,int st,int ed){
ull ans =0;for(int i = ed -1; i >= st;--i){
ans = ans * seed + s[i]-'a'+1;}return ans;}
bool a[N]={
false }, b[N]={
false };
ull Ahash[N], Bhash[N];
unordered_map<ull, bool>vis;
vector<pii>vec[N];intmain(){
#ifdef _DEBUG
FILE* _INPUT =freopen("input.txt","r",stdin);// FILE* _OUTPUT = freopen("output.txt", "w", stdout);#endif
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> m >> n;
vector<string>A(m),B(n);for(auto& v : A) cin >> v;for(auto& v : B) cin >> v;sort(A.begin(), A.end(), cmp);sort(B.begin(), B.end(), cmp);for(int i =0; i < m;++i){
if(!i){
ull tmp =prefHash(A[i],0, A[i].size());
hash_A[tmp]=1;
Ahash[i]= tmp;continue;}
ull ans =0;for(int j =0; j < A[i].size();++j){
ans = ans * seed + A[i][j]-'a'+1;if(hash_A[ans]){
ull tmp =prefHash(A[i], j +1, A[i].size());
suff[tmp]=1;
vec[i].push_back({
tmp,ans });}}
hash_A[ans]=1;
Ahash[i]= ans;}for(int i =0; i < n;++i){
if(!i){
ull tmp =suffHash(B[i],0, B[i].size());
hash_B[tmp]=1;
Bhash[i]= tmp;continue;}
ull ans =0;for(int j = B[i].size()-1; j >=0;--j){
ans = ans * seed + B[i][j]-'a'+1;if(hash_B[ans]){
ull tmp =prefHash(B[i],0, j);
pref[tmp]=1;if(suff[tmp])
b[i]=1, vis[ans]=1;}}
hash_B[ans]=1;
Bhash[i]= ans;}for(int i =0; i < n;++i){
if(vis[Bhash[i]]) b[i]=1;}
vis.clear();for(int i =1; i < m;++i){
for(auto v : vec[i]){
if(pref[v.first]) a[i]=1, vis[v.second]=1;}}for(int i =0; i < m;++i){
if(a[i])continue;if(vis[Ahash[i]]) a[i]=1;}int ans1 =0, ans2 =0;for(int i =0; i < m;++i) ans1 +=!a[i];for(int i =0; i < n;++i) ans2 +=!b[i];
cout << ans1 <<" "<< ans2 <<'\n';return0;}
在需要数量是所有叶子结点的情况下,现考虑两个状态, d p [ N ] [ 2 ] dp[N][2] dp[N][2]
若当前点需要查询,则记录为 d p [ i ] [ 1 ] dp[i][1] dp[i][1] ;否则若不需要查询,则记录为 d p [ i ] [ 0 ] dp[i][0] dp[i][0]
当不需要查询的时候, d p [ i ] [ 0 ] = ∏ d p [ v ] [ 0 ] dp[i][0]=\prod dp[v][0] dp[i][0]=∏dp[v][0] ,其中 v v v 是 i i i 的子结点
当需要查询的时候, d p [ i ] [ 1 ] = ∏ d p [ v k ] [ 0 ] ∗ d p [ v j ] [ 1 ] dp[i][1]=\prod dp[v_k][0]*dp[v_j][1] dp[i][1]=∏dp[vk][0]∗dp[vj][1] ,其中 j ≠ k j\ne k j=k
最后需要 d p [ i ] [ 0 ] + = d p [ i ] [ 1 ] dp[i][0]+=dp[i][1] dp[i][0]+=dp[i][1] 表示在当前点进行查询; d p [ i ] [ 1 ] dp[i][1] dp[i][1] 表示在当前点未进行查询并且仍欠一个查询。
因为直接对乘数积乘逆元会出错,下面代码采用左右两段来进行乘法运算
#include<bits/stdc++.h>
using namespace std;typedeflonglong ll;typedefunsignedlonglong ull;typedef pair<int,int> pii;
template<typename T>inlinevoidrd(T& x){
int tmp =1;char c =getchar(); x =0;while(c >'9'|| c <'0'){
if(c =='-')tmp =-1; c =getchar();}while(c >='0'&& c <='9'){
x = x *10+ c -'0'; c =getchar();}
x *= tmp;}constint N =3e5+10;constint M =1e7+10;constint mod =1e9+7, inf =0x3f3f3f3f;
ll gcd(ll x, ll y){
if(y ==0)return x;returngcd(y, x % y);}int head[N], cntE =0;struct edge {
int next, to, w;}e[M];voidadd(int u,int v,int w =0){
e[cntE].to = v;
e[cntE].next = head[u];
e[cntE].w = w;
head[u]= cntE++;}
ll fp(ll x, ll y){
ll ans =1;while(y){
if(y &1) ans = ans * x % mod;
x = x * x % mod;
y >>=1;}return ans;}int n, m;
ll dp[N][2];
ll pre[N], last[N];voiddfs(int x){
if((~head[x])==0){
dp[x][0]= dp[x][1]=1;return;}
dp[x][0]=1;
vector<ll>vec;for(int i = head[x];~i; i = e[i].next){
int v = e[i].to;dfs(v);
dp[x][0]*= dp[v][0];
dp[x][0]%= mod;
vec.push_back(dp[v][0]);}int sz = vec.size();
pre[0]= vec[0];last[sz -1]= vec[sz -1];
last[sz]=1;for(int i =1; i < sz;++i) pre[i]= pre[i -1]* vec[i]% mod;for(int i = sz -2; i >=0;--i) last[i]= last[i +1]* vec[i]% mod;
dp[x][1]=0;int pos =0;for(int i = head[x];~i; i = e[i].next,++pos){
int v = e[i].to;if(pos ==0) dp[x][1]+= last[pos +1]* dp[v][1]% mod;elseif(pos == sz -1) dp[x][1]+= pre[pos -1]* dp[v][1]% mod;else dp[x][1]+= pre[pos -1]* last[pos +1]% mod * dp[v][1]% mod;
dp[x][1]= dp[x][1]< mod ? dp[x][1]: dp[x][1]- mod;}
dp[x][0]+= dp[x][1];
dp[x][0]= dp[x][0]< mod ? dp[x][0]: dp[x][0]- mod;}intmain(){
#ifdef _DEBUG
FILE* _INPUT =freopen("input.txt","r",stdin);// FILE* _OUTPUT = freopen("output.txt", "w", stdout);#endifrd(n);memset(head,-1,sizeof(int)*(n +10)); cntE =0;for(int i =2; i <= n;++i){
int x;rd(x);add(x, i);}dfs(1);printf("%lld\n", dp[1][0]);return0;}
K. Between Us
根据题目意思,每个人只有两个阵营可选, 设 a i = 0 a_i=0 ai=0 表示 i i i 选择第一个阵营, a i = 1 a_i=1 ai=1 表示第二个阵营
现考虑 i i i 有奇数个朋友,朋友数量为 k k k,因为奇=奇+偶
假设 a i = 0 a_i=0 ai=0 则必须有奇数个 a j = 0 a_j=0 aj=0 ,剩下偶数个 a j = 1 a_j=1 aj=1
假设 a i = 1 a_i=1 ai=1 则必须有奇数个 a j = 1 a_j=1 aj=1 ,剩下偶数个 a j = 0 a_j=0 aj=0
由上可推出一个规律 a j 1 ⊕ a j 2 . . . ⊕ a j k = a i a_{j_1}\oplus a_{j_2}...\oplus a_{j_k}=a_i aj1⊕aj2...⊕ajk=ai
现考虑朋友数量为偶数,因为奇+奇=偶:
无论 a i a_i ai 为何值,必定是奇数个 a j = 1 a_j=1 aj=1 ,奇数个 a j = 0 a_j=0 aj=0
所以满足 a j 1 ⊕ a j 2 . . . ⊕ a j k = 1 a_{j_1}\oplus a_{j_2}...\oplus a_{j_k}=1 aj1⊕aj2...⊕ajk=1
当所有的方程式出来后,直接看方程是否有解即可,最终是一个 n ∗ ( n + 1 ) n*(n+1) n∗(n+1) 增广矩阵,先进行高斯消元,而后判断:若当前行 a i , 1 . . . a i , n a_{i,1}...a_{i,n} ai,1...ai,n 都为0并且 a i , n + 1 a_{i,n+1} ai,n+1 不为0,此时无解。
#include<bits/stdc++.h>
using namespace std;typedeflonglong ll;typedefunsignedlonglong ull;typedef pair<int,int> pii;
template<typename T>inlinevoidrd(T& x){
int tmp =1;char c =getchar(); x =0;while(c >'9'|| c <'0'){
if(c =='-')tmp =-1; c =getchar();}while(c >='0'&& c <='9'){
x = x *10+ c -'0'; c =getchar();}
x *= tmp;}constint N =1e2+10;constint M =1e7+10;constint mod =1e9+7, inf =0x3f3f3f3f;
ll gcd(ll x, ll y){
if(y ==0)return x;returngcd(y, x % y);}int head[N], cntE =0;struct edge {
int next, to, w;}e[M];voidadd(int u,int v,int w =0){
e[cntE].to = v;
e[cntE].next = head[u];
e[cntE].w = w;
head[u]= cntE++;}int n, m;int d[N]={
0};
bitset<N <<1>a[N];intGauss_rev(int n){
int rank =0;for(int i =1; i <= n; i++){
for(int j = i; j <= n; j++){
if(a[j][i]){
swap(a[i], a[j]);break;}}if(!a[i][i])continue;else++rank;for(int j =1; j <= n; j++){
if(a[j][i]&& j != i){
a[j]^= a[i];}}}for(int i =1; i <= n;++i){
if(!a[i][n +1])continue;
bool flag = false;for(int j =1; j <= n;++j){
if(a[i][j]){
flag = true;break;}}if(!flag)return0;}return1;}
vector<int>G[N];intmain(){
#ifdef _DEBUG
FILE* _INPUT =freopen("input.txt","r",stdin);// FILE* _OUTPUT = freopen("output.txt", "w", stdout);#endifrd(n);rd(m);while(m--){
int x, y;rd(x),rd(y);
G[x].push_back(y);
G[y].push_back(x);}for(int i =1; i <= n;++i){
a[i].reset();for(auto v : G[i]) a[i][v]=1;if(G[i].size()&1) a[i][i]=1;else a[i][n +1]=1;}if(!Gauss_rev(n))puts("N");elseputs("Y");return0;}
L. Lavaspar
这题考虑暴力的做即可
对每个单词逐个处理
从上至下从左至右遍历所有点,对于一个点,可以选择四个方向扫描:右边,下边,左下,右下
每次扫描的时候记录好字母出现次数,全部符合便标记扫描的所有位置
#include<bits/stdc++.h>
using namespace std;typedeflonglong ll;constint N =2e6+10;constint INF =0x3f3f3f3f;int l, c, vis[50][50], cnt[50][50];char a[50][50];char s[50];int snum[26], temp[26];
bool check(){
for(int i =0;i <26;++i)if(snum[i]!= temp[i])return false;return true;}voidwork(int si,int sj,int len,int flag){
if(flag ==1){
for(int k = sj;k <= sj + len -1;++k) vis[si][k]=1;}elseif(flag ==2){
for(int k = si;k <= si + len -1;++k) vis[k][sj]=1;}elseif(flag ==3){
for(int k =0;k < len;++k) vis[si + k][sj + k]=1;}else{
for(int k =0;k < len;++k) vis[si + k][sj - k]=1;}}intmain(){
scanf("%d%d",&l,&c);for(int i =1;i <= l;++i)scanf("%s", a[i]+1);int n;scanf("%d",&n);while(n--){
memset(vis,0,sizeof vis);memset(snum,0,sizeof snum);scanf("%s", s);int len =strlen(s);for(int i =0;i < len;++i) snum[s[i]-'A']++;for(int i =1;i <= l;++i){
for(int j =1;j <= c;++j){
memset(temp,0,sizeof temp);if(c - j +1>= len){
for(int k = j;k <= j + len -1;++k) temp[a[i][k]-'A']++;if(check())work(i, j, len,1);}memset(temp,0,sizeof temp);if(l - i +1>= len){
for(int k = i;k <= i + len -1;++k) temp[a[k][j]-'A']++;if(check())work(i, j, len,2);}memset(temp,0,sizeof temp);if(min(c - j +1, l - i +1)>= len){
for(int k =0;k < len;++k) temp[a[i + k][j + k]-'A']++;if(check())work(i, j, len,3);}memset(temp,0,sizeof temp);if(min(j, l - i +1)>= len){
for(int k =0;k < len;++k) temp[a[i + k][j - k]-'A']++;if(check())work(i, j, len,4);}}}for(int i =1;i <= l;++i)for(int j =1;j <= c;++j)if(vis[i][j]) cnt[i][j]++;}int ans =0;for(int i =1;i <= l;++i){
for(int j =1;j <= c;++j){
if(cnt[i][j]>1) ans++;}}printf("%d\n", ans);return0;}
M. Machine Gun
显然,对于每个点,有两个边界,分别是斜率 k = 1 2 k=\frac{1}{2} k=21 以及 k = − 1 2 k=-\frac{1}{2} k=−21, 令 x = 0 x=0 x=0 ,求出对应边界的 y y y 值
给定一个查询的点 x , y x,y x,y ,求出该点的上界 y 1 = 2 ∗ y − x , y 2 = 2 ∗ y + x y_1=2*y-x,y_2=2*y+x y1=2∗y−x,y2=2∗y+x
此后便化成了个二维偏序问题,现假设先按照上界排,对于每个上界的 y 1 y_1 y1 值,在这个值当中存放了右边点中上界点 ≤ y 1 \le y_1 ≤y1 的所有点,对这个所有点进行排序后筛选出下界 ≥ y 2 \ge y_2 ≥y2 的点,按照题目的要求操作即可。
问题是该怎么去存上界 ≤ y 1 \le y_1 ≤y1 的所有点,对每一个 y 1 y_1 y1 都存是不现实的,时间不允许,空间也不允许。可以使用主席树来继承。
下面考虑一种方法,使用树状数组来存点,以优化时间和空间。详情看代码:
#include<bits/stdc++.h>
using namespace std;typedeflonglong ll;typedefunsignedlonglong ull;typedef pair<ll,int> pii;typedef pair<ll, ll>pll;
template<typename T>inlinevoidrd(T& x){
int tmp =1;char c =getchar(); x =0;while(c >'9'|| c <'0'){
if(c =='-')tmp =-1; c =getchar();}while(c >='0'&& c <='9'){
x = x *10+ c -'0'; c =getchar();}
x *= tmp;}constint N =2e5+10;constint M =1e7+10;constint mod =1e9+7;const ll inf =1e16;const ll NUM =5782344;
ll gcd(ll x, ll y){
if(y ==0)return x;returngcd(y, x % y);}
vector<pii>vec[N];inlineintlowbit(int x){
return x &(-x);}voidadd(int x,ll y,int num){
while(x <= N -10){
vec[x].push_back({
y,num });
x +=lowbit(x);}}
vector<int>get(int x,ll y){
vector<int>ans;while(x){
for(auto v : vec[x]){
if(v.first < y)break;
ans.push_back(v.second);}
x -=lowbit(x);}return ans;}int n, m;struct node {
ll l, r;int id;}a[N];
ll fac[N];
ll b[N];intmain(){
#ifdef _DEBUG
FILE* _INPUT =freopen("input.txt","r",stdin);// FILE* _OUTPUT = freopen("output.txt", "w", stdout);#endifrd(n),rd(m);for(int i =1; i <= n;++i){
ll x, y;rd(x),rd(y);
b[i]= a[i].l =2LL* y - x;
a[i].r =2LL* y + x;
a[i].id = i;}sort(b +1, b +1+ n);int n1 = n;
n1 =unique(b +1, b +1+ n)- b -1;for(int i =1; i <= n;++i){
int pos =lower_bound(b +1, b +1+ n1, a[i].l)- b;add(pos , a[i].r, i);}for(int i =0; i <= N -5;++i)sort(vec[i].rbegin(), vec[i].rend());
fac[0]=1;for(int i =1; i <= N -5;++i) fac[i]= fac[i -1]* NUM % mod;
ll p =0;while(m--){
ll aa, bb;rd(aa),rd(bb);
ll x =-1LL-((p + aa)% mod);
ll y =(p + bb)% mod;
ll tmpl = y *2- x;
ll tmpr = y *2+ x;int posl =upper_bound(b +1, b +1+ n1, tmpl)- b -1;
vector<int>vec1 =get(posl, tmpr);sort(vec1.begin(), vec1.end());int cnt =0;
ll ans =0;for(auto v : vec1){
ans +=1LL* v * fac[cnt++]% mod;
ans = ans < mod ? ans : ans - mod;}printf("%lld\n", ans);
p = ans;}return0;}
N. Number Multiplication
对于这题可以考虑暴力的做法,对于 c i c_i ci 至多 1 0 15 10^{15} 1015 ,进行欧拉筛法就需要进行到 1 0 15 < 31622777 \sqrt{10^{15}}<31622777 1015<31622777
对于 3 e 7 3e7 3e7 的线性筛法时间还是够的,后面就根据每个数进行质因数分解
因为题目给出的质因子是从小到大排,对每个质因数分解后直接对号入座即可。
为了避免超时加一个优化,使用 s e t set set 将所有质因子的下标装进去,若已经知道该下标的值,则删去从 s e t set set 中删除这个点;若 s e t set set 空了直接跳出。
#include<bits/stdc++.h>
using namespace std;typedeflonglong ll;typedef pair<int,int> pii;constint N =1e3+10;constint INF =0x3f3f3f3f;constint M =31622776+10;inline ll rd(){
ll x =0, f =1;char ch =getchar();while(ch <'0'|| ch >'9'){
if(ch =='-')
f =-1;
ch =getchar();}while(ch >='0'&& ch <='9'){
x =(x <<1)+(x <<3)+(ch ^48);
ch =getchar();}return x * f;}int n, m, k;int prime[M], cnt =0;
bool isprime[M];voidinit(){
for(int i =2;i <= M -10;++i){
if(!isprime[i]) prime[++cnt]= i;for(int j =1;j <= cnt && prime[j]* i <= M -10;++j){
isprime[i * prime[j]]= true;if(i % prime[j]==0)break;}}}
ll c[N];struct node {
ll id, cnt;node(ll id =0, ll cnt =0):id(id),cnt(cnt){
}
bool friend operator<(const node& a,const node& b){
return a.cnt < b.cnt || a.cnt == b.cnt && a.id < b.id;}};
vector<node>vec[N];
vector<node>G[N];
ll p[N];intmain(){
init();// scanf("%d %d %d", &m, &n, &k);
m =rd(), n =rd(), k =rd();
set<int>s;for(int i =1;i <= m;++i) s.insert(i);for(int i =1;i <= n;++i) c[i]=rd();for(int i =1;i <= k;++i){
int x, y, d;x =rd(), y =rd(), d =rd();
vec[y].push_back(node(x, d));}for(int i =1;i <= n;++i){
ll tmp = c[i];
G[i].resize(vec[i].size());int pos =0;for(int j =1;j <= cnt &&1LL* prime[j]* prime[j]<= tmp;++j){
if(tmp % prime[j]==0){
int tot =0;while(tmp % prime[j]==0) tmp /= prime[j],++tot;
G[i][pos++]=(node(prime[j], tot));}}if(tmp >1) G[i][pos++]=(node(tmp,1));sort(vec[i].begin(), vec[i].end());sort(G[i].begin(), G[i].end());for(int j =0;j < vec[i].size();++j){
p[vec[i][j].id]= G[i][j].id;auto v = s.find(vec[i][j].id);if(v != s.end()) s.erase(v);}if(s.empty())break;}for(int i =1;i <= m;++i)printf("%lld%s", p[i], i == m ?"\n":" ");return0;}