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;}