本来是8天代码放一起的,但是太麻烦了,还是分成了2个博客放。
day5
5H div2 Nested Tree (树形dp)
//H
#include<bits/stdc++.h>
#define fi first
#define se second
#define iis std::ios::sync_with_stdio(false)
#define pb push_back
#define o2(x) (x)*(x)
using namespace std;
typedef long long LL;
typedef pair<int, LL> pii;
const int MXN = 2e6 + 6;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
LL n, m;
std::vector<int> mp[MXN];
LL siz[MXN];
LL ans;
void dfs(int u,int ba) {
siz[u] = 1;
for(auto v: mp[u]) {
if(v == ba) continue;
dfs(v, u);
siz[u] += siz[v];
ans += siz[v] *(n*m-siz[v])%mod;
ans = (ans%mod + mod)%mod;
}
}
int main(){
scanf("%lld%lld", &n, &m);
for(int i = 1, a, b; i < n; ++i) {
scanf("%d%d", &a, &b);
for(int j = 0; j < m; ++j) {
mp[a+j*n].push_back(b+j*n);
mp[b+j*n].push_back(a+j*n);
}
}
for(int i = 1, a, b, u, v; i < m; ++i) {
scanf("%d%d%d%d", &a, &b, &u, &v); --a, --b;
mp[a*n+u].push_back(b*n+v);
mp[b*n+v].push_back(a*n+u);
}
dfs(1, 1);
printf("%lld\n", ans);
return 0;
}
5F div2 Kropki (状压dp)
//F
#include<bits/stdc++.h>
#define fi first
#define se second
#define iis std::ios::sync_with_stdio(false)
#define pb push_back
#define o2(x) (x)*(x)
using namespace std;
typedef long long LL;
typedef pair<int, LL> pii;
const int MXN = 2e6 + 6;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
int n, m;
LL dp[1<<16][16];
char s[MXN];
int get_num(int x) {
bitset<40> sb(x);
return sb.count();
}
int main(){
scanf("%d%s", &n, s+1);
memset(dp, 0, sizeof(dp));
for(int i = 0; i < n; ++i) {
dp[1<<i][i] = 1;
}
int sta = 1<<n;
for(int t = 1; t < sta; ++t) {
for(int i = 0; i < n; ++i) {
if(!(t & (1 << i))) continue;
for(int j = 0; j < n; ++j) {
if(i == j) continue;
if(!(t&(1<<j))) continue;
int old = t^(1<<i);
if(dp[old][j] == -1) continue;
int h = get_num(old);
if(h == 0) continue;
if(s[h] == '1' && ((j+1)*2 == i+1||(i+1)*2==j+1)) {
//if(dp[t][i] == -1) dp[t][i] = 0;
dp[t][i] += dp[old][j];
}else if(s[h] == '0' && (j+1)*2!=i+1&&(i+1)*2!=j+1){
//if(dp[t][i] == -1) dp[t][i] = 0;
dp[t][i] += dp[old][j];
}
if(dp[t][i] >= mod) dp[t][i] %= mod;
}
}
}
LL ans = 0;
for(int i = 0; i < n; ++i) {
if(dp[sta-1][i] == -1) continue;
ans = (ans + dp[sta-1][i]) % mod;
}
printf("%lld\n", ans);
return 0;
}
5J div1 Special Judge (计算几何)
//J
#include<bits/stdc++.h>
#define fi first
#define se second
#define iis std::ios::sync_with_stdio(false)
#define pb push_back
#define o2(x) (x)*(x)
#define db LL
using namespace std;
typedef long long LL;
typedef pair<int, LL> pii;
#define cross(p1,p2,p3) ((p2.x-p1.x)*(p3.y-p1.y)-(p3.x-p1.x)*(p2.y-p1.y))
#define crossOp(p1,p2,p3) sign(cross(p1,p2,p3))
const int MXN = 1e5 + 6;
const int INF = 0x3f3f3f3f;
const double eps = 1e-9;
int n, m;
struct P {
db x, y;
P(){};
P(db _x, db _y):x(_x),y(_y){}
P operator+(P p){return {x+p.x,y+p.y};}
P operator-(P p){return {x-p.x,y-p.y};}
db dot(P p) {return x*p.x+y*p.y;}
db det(P p) {return x*p.y-y*p.x;}
};
inline int sign(db a) {return a < -eps?-1:a>eps;}
inline int cmp(db a, db b) {return sign(a-b);}
bool intersect(db l1, db r1, db l2, db r2) {
if(l1 > r1) swap(l1, r1);if(l2 > r2) swap(l2, r2);
return !(cmp(r1,l2)==-1||cmp(r2,l1)==-1);
}
bool isSS(P p1, P p2, P q1, P q2) {//判断线段相交
return intersect(p1.x,p2.x,q1.x,q2.x)&&intersect(p1.y,p2.y,q1.y,q2.y)&&
crossOp(p1,p2,q1)*crossOp(p1,p2,q2)<=0&&crossOp(q1,q2,p1)*crossOp(q1,q2,p2)<=0;
}
bool isSS_strict(P p1, P p2, P q1, P q2) {//严格相交
return crossOp(p1,p2,q1)*crossOp(p1,p2,q2)<0&&crossOp(q1,q2,p1)
*crossOp(q1,q2,p2) < 0;
}
bool isMiddle(db a, db m, db b) {
return sign(a-m)==0||sign(b-m)==0||(a<m!=b<m);
}
bool isMiddle(P a, P m, P b) {
return isMiddle(a.x,m.x,b.x)&&isMiddle(a.y,m.y,b.y);
}
bool onSeg(P p1, P p2, P q) {
return crossOp(p1,p2,q) == 0 && isMiddle(p1,q,p2);
}
bool ojbk(P p1, P p2, P q1, P q2) {
P p = p2 - p1;
P q = q2 - q1;
if(q.det(p) == 0) return 1;
return 0;
}
double rad(P p1, P p2) {
return atan2(p1.det(p2),p1.dot(p2));
}
bool xielv(P p1, P p2, P q1, P q2) {
P p = p2 - p1;
P q = q2 - q1;
if(q.det(p) == 0 && cmp(rad(p, q), 0) == 0) return 1;
return 0;
}
struct lp {
int a, b;
}cw[MXN];
LL x[MXN], y[MXN];
int main(){
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; ++i) {
scanf("%d%d", &cw[i].a, &cw[i].b);
}
for(int i = 1; i <= n; ++i) {
scanf("%lld%lld", &x[i], &y[i]);
}
int cnt = 0;
for(int i = 1; i <= m; ++i) {
for(int j = i + 1; j <= m; ++j) {
P p1 = {x[cw[i].a],y[cw[i].a]};
P p2 = {x[cw[i].b],y[cw[i].b]};
P q1 = {x[cw[j].a],y[cw[j].a]};
P q2 = {x[cw[j].b],y[cw[j].b]};
//printf("%d %d %d %d\n", cw[i].a, cw[i].b, cw[j].a, cw[j].b);
//printf("%lld %lld\n", q2.x,q2.y);
if(isSS(p1,p2,q1,q2)) {
if(cw[i].a==cw[j].a || cw[i].a==cw[j].b||cw[i].b==cw[j].a||cw[i].b==cw[j].b) {
//printf("%lld %lld %lld %lld %lld %lld %lld %lld\n", p1.x,p1.y,p2.x,p2.y,q1.x,q1.y,q2.x,q2.y);
if(cw[i].a==cw[j].a&&xielv(p1,p2,q1,q2)) cnt++;
if(cw[i].a==cw[j].b&&xielv(p1,p2,q2,q1)) cnt++;
if(cw[i].b==cw[j].a&&xielv(p2,p1,q1,q2)) cnt++;
if(cw[i].b==cw[j].b&&xielv(p2,p1,q2,q1)) cnt++;
}else cnt++;
}
}
}
printf("%d\n", cnt);
return 0;
}
5I div1 Sorting (线段树)
//I
#include<bits/stdc++.h>
#define fi first
#define se second
#define iis std::ios::sync_with_stdio(false)
#define pb push_back
#define o2(x) (x)*(x)
using namespace std;
typedef long long LL;
typedef pair<int, LL> pii;
const int MXN = 1e6 + 6;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
int n, q, x;
int ar[MXN];
int sum1[MXN<<2], sum2[MXN<<2], flag[MXN<<2];
LL num1[MXN], num2[MXN];
void push_up(int rt) {
sum1[rt] = sum1[rt<<1] + sum1[rt<<1|1];
sum2[rt] = sum2[rt<<1] + sum2[rt<<1|1];
}
void build(int l,int r,int rt) {
flag[rt] = -1;
if(l == r) {
if(ar[l] > x) sum2[rt] = 1;
else sum1[rt] = 1;
return;
}
int mid = (l + r) >> 1;
build(l, mid,rt<<1); build(mid+1, r,rt<<1|1);
push_up(rt);
}
void push_down(int l,int mid,int r,int rt) {
if(flag[rt] == -1) return ;
flag[rt<<1] = flag[rt];
flag[rt<<1|1] = flag[rt];
if(flag[rt] == 0) {
sum1[rt<<1] = mid-l+1;
sum1[rt<<1|1] = r-mid;
sum2[rt<<1] = 0;
sum2[rt<<1|1] = 0;
}else {
sum1[rt<<1] = 0;
sum1[rt<<1|1] = 0;
sum2[rt<<1] = mid-l+1;
sum2[rt<<1|1] = r-mid;
}
flag[rt] = -1;
}
void update(int L, int R,int v,int l,int r,int rt) {
if(L > R) return ;
if(L <= l && r <= R) {
if(v == 0) sum1[rt] = r - l + 1,sum2[rt] = 0;
else sum2[rt] = r - l + 1,sum1[rt] = 0;
flag[rt] = v;
return;
}
int mid = (l + r) >> 1;
push_down(l, mid, r, rt);
if(L > mid) update(L, R, v,mid+1,r,rt<<1|1);
else if(R <= mid) update(L,R,v,l,mid,rt<<1);
else {
update(L,mid,v,l,mid,rt<<1), update(mid+1,R,v,mid+1,r,rt<<1|1);
}
push_up(rt);
}
int query1(int L,int R,int l,int r,int rt,int id) {
if(L > R) return 0;
if(L <= l && r <= R) {
if(id == 0)return sum1[rt];
return sum2[rt];
}
int mid = (l + r) >> 1;
push_down(l, mid, r, rt);
if(L > mid) return query1(L, R, mid+1,r,rt<<1|1,id);
else if(R <= mid) return query1(L,R,l,mid,rt<<1,id);
else {
return query1(L,mid,l,mid,rt<<1,id) + query1(mid+1,R,mid+1,r,rt<<1|1,id);
}
}
int main(){
scanf("%d%d%d", &n, &q, &x);
for(int i = 1; i <= n; ++i) scanf("%d", &ar[i]);
int cnt1 = 0, cnt2 = 0;
for(int i = 1; i <= n; ++i) {
if(ar[i] <= x) ++ cnt1, num1[cnt1] = num1[cnt1-1]+ar[i];
else ++ cnt2, num2[cnt2] = num2[cnt2-1]+ar[i];
}
build(1, n, 1);
int p, l, r;
while(q --) {
scanf("%d%d%d", &p, &l, &r);
if(p == 1) {
int p0 = query1(1,l-1,1,n,1,0), p1 = query1(1,r,1,n,1,0);
int q0 = query1(1,l-1,1,n,1,1), q1 = query1(1,r,1,n,1,1);
printf("%lld\n", num1[p1] - num1[p0] + num2[q1] - num2[q0]);
}else if(p == 2) {
int sb1 = query1(l,r,1,n,1,0);
if(sb1) update(l,l+sb1-1,0,1,n,1);
update(l+sb1,r,1,1,n,1);
}else {
int sb2 = query1(l,r,1,n,1,1);
if(sb2) update(l,l+sb2-1,1,1,n,1);
update(l+sb2,r,0,1,n,1);
}
}
return 0;
}
5D div1 Doppelblock (搜索)
//D杨栩
#include<bits/stdc++.h>
#define fi first
#define se second
#define iis std::ios::sync_with_stdio(false)
#define pb push_back
#define o2(x) (x)*(x)
using namespace std;
typedef long long LL;
typedef pair<int, LL> pii;
const int MXN = 2e6 + 6;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
int n;
int vis[15][15];
int visr[15][15];
int visc[15][15];
int needr[15];
int needc[15];
int nowrx[15],nowcx[15];// di i 行 第一个x的纵坐标 竖 横坐标
int haverx[15],havecx[15];
int nowc[15],nowr[15];
int totc[15],totr[15];
int flag = 0;
int sum;
bool check() {
for(int i=1; i<=n; i++) {
if(havecx[i]!=2 || haverx[i]!=2) {
return 0;
}
}
return 1;
}
void dfs(int x,int y) {
//cout<<"now:"<<x<<","<<y<<",,"<<flag<<endl;
if(haverx[x]==0 && sum-totr[x]<needr[x]) return;
if(havecx[y]==0 && sum-totc[y]<needc[y]) return;
if(flag ) return ;
if(x==n+1) {
if(check())
flag = 1;
//cout<<"haha:"<<flag<<endl;
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
if(vis[i][j]!=-1) {
printf("%d",vis[i][j]);
} else {
printf("X");
}
}
puts("");
}
return ;
}
// for(int i=1; i<=n; i++) {
// for(int j=1; j<=n; j++) {
// if(vis[i][j]!=-1) {
// printf("%d",vis[i][j]);
// } else {
// printf("X");
// }
// }
// puts("");
// }
// 判断是否可放x
if(haverx[x]==0 &&havecx[y]==0) {
nowrx[x]=y;
nowcx[y]=x;
havecx[y]++;
haverx[x]++;
vis[x][y]=-1;
if(y+1>n) {
if(haverx[x]==2)
dfs(x+1,1);
} else {
dfs(x,y+1);
}
vis[x][y]=0;
nowrx[x]=0;
nowcx[y]=0;
havecx[y]--;
haverx[x]--;
}
// 横有了一个x 竖没有x
else if(haverx[x]==1 && havecx[y]==0) {
int cnt = nowr[x];//getnum(nowrx[x],y,x,1);
//cout<<"cnt:"<<cnt<<endl;
// 第 i 行 两个x之间的属的和满足ri
if(cnt==needr[x]) {
havecx[y]++;
haverx[x]++;
nowcx[y]=x;
vis[x][y]=-1;
if(y+1>n) {
if(haverx[x]==2)
dfs(x+1,1);
} else {
dfs(x,y+1);
}
vis[x][y]=0;
havecx[y]--;
haverx[x]--;
nowcx[y]=0;
}
}
// 竖有了一个x 横没有x
else if(haverx[x]==0 && havecx[y]==1) {
int cnt = nowc[y];//getnum(nowcx[y],x,y,0);
// 第 i 行 两个x之间的属的和满足ri
if(cnt==needc[y]) {
havecx[y]++;
haverx[x]++;
nowrx[x]=y;
vis[x][y]=-1;
if(y+1>n) {
if(haverx[x]==2)
dfs(x+1,1);
} else {
dfs(x,y+1);
}
vis[x][y]=0;
havecx[y]--;
haverx[x]--;
nowrx[x]=0;
}
}// 横竖都有一个
else {
int cnt1 = nowr[x];//getnum(nowrx[x],y,x,1);
int cnt2 = nowc[y];//getnum(nowcx[y],x,y,0);
if(cnt1 == needr[x] && cnt2 == needc[y]) {
havecx[y]++;
haverx[x]++;
vis[x][y]=-1;
if(y+1>n) {
if(haverx[x]==2)
dfs(x+1,1);
} else {
dfs(x,y+1);
}
vis[x][y]=0;
havecx[y]--;
haverx[x]--;
}
}
for(int i=1; i<=n-2; i++) {
int cnt1 = 0;
if(haverx[x]==1) {
cnt1 =nowr[x];//getnum(nowrx[x],y,x,1);
if(cnt1+i>needr[x]) continue;
//cout<<"cnt1+i:"<<cnt1+i<<"vs"<<needr[x]<<endl;
}
int cnt2 = 0;
if(havecx[y]==1) {
cnt2 = nowc[y];//getnum(nowcx[y],x,y,0);
if(cnt2+i>needc[y]) continue;
}
if(visc[y][i]==0 && visr[x][i]==0 ) {
visc[y][i]=1;
visr[x][i]=1;
vis[x][y]=i;
totc[y]+=i;
totr[x]+=i;
if(haverx[x]==1) {
nowr[x]+=i;
}
if(havecx[y]==1) {
nowc[y]+=i;
}
if(y+1>n) {
if(haverx[x]==2)
dfs(x+1,1);
} else {
dfs(x,y+1);
}
if(haverx[x]==1) {
nowr[x]-=i;
}
if(havecx[y]==1) {
nowc[y]-=i;
}
totc[y]-=i;
totr[x]-=i;
visc[y][i]=0;
visr[x][i]=0;
vis[x][y]=0;
}
}
}
void init() {
flag = 0;
memset(vis,0,sizeof vis);
memset(visr,0,sizeof visr);
memset(visc,0,sizeof visc);
memset(needr,0,sizeof needr);
memset(needc,0,sizeof needc);
memset(nowrx,0,sizeof nowrx);
memset(nowcx,0,sizeof nowcx);
memset(haverx,0,sizeof haverx);
memset(havecx,0,sizeof havecx);
memset(nowc,0,sizeof nowc);
memset(nowr,0,sizeof nowr);
memset(totc,0,sizeof totc);
memset(totr,0,sizeof totr);
sum=0;
for(int i=1; i<=n-2; i++) {
sum+=i;
}
// cout<<sum<<endl;
}
int main() {
int T;
scanf("%d",&T);
while(T--) {
scanf("%d",&n);
init();
for(int i=1; i<=n; i++) {
scanf("%d",&needr[i]);
}
for(int j=1; j<=n; j++) {
scanf("%d",&needc[j]);
}
dfs(1,1);
if(T)
puts("");
}
}
5C div1 Division (主席树)
//C
题解:https://blog.csdn.net/qq_39599067/article/details/86650060
#include<bits/stdc++.h>
#define fi first
#define se second
#define iis std::ios::sync_with_stdio(false)
#define pb push_back
#define o2(x) (x)*(x)
using namespace std;
typedef long long LL;
typedef pair<int, LL> pii;
const int MXN = 1e6 + 6;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
int n, q;
int ar[MXN], num[MXN];
LL sum[MXN];
struct QUERY {
int l, r, k;
LL ans;
}cw[MXN];
struct lp {
int l, r, cnt;
LL sum;
}node[MXN*16];
int inde, Root[MXN];
void z_update(int old, int &cur, int val, LL L, LL R) {
cur = ++ inde;
node[cur] = node[old];
if(L == R) {
node[cur].sum += val - val/2;
++ node[cur].cnt;
return;
}
LL mid = (L + R) / 2;
if(val <= mid) z_update(node[old].l, node[cur].l, val, L, mid);
else z_update(node[old].r, node[cur].r, val, mid+1, R);
node[cur].sum = node[node[cur].l].sum + node[node[cur].r].sum;
node[cur].cnt = node[node[cur].l].cnt + node[node[cur].r].cnt;
}
LL z_query(int k, int old, int cur, LL L, LL R) {
if(L == R) {
return (LL)k*(L-L/2);
}
LL mid = (L + R) / 2;
int tmp = node[node[cur].r].cnt - node[node[old].r].cnt;
if(k <= tmp) {
return z_query(k, node[old].r, node[cur].r, mid + 1, R);
}else {
return node[node[cur].r].sum - node[node[old].r].sum
+ z_query(k-tmp, node[old].l, node[cur].l, L, mid);
}
}
/*LL query(int k, int old, int cur, int L, LL R) {
printf("%d %lld %lld\n", k, node[cur].sum, node[old].sum);
if(L == R) {
printf("*%d %d\n", L,k*(L-L/2));
return (LL)k*(L-L/2);
}
LL mid = (L + R) / 2;
int tmp = node[node[cur].r].cnt - node[node[old].r].cnt;
printf("%d %d %d %d %lld\n", k, tmp, node[node[old].r].cnt,node[node[cur].r].cnt,node[node[cur].r].sum - node[node[old].r].sum);
if(k <= tmp) {
return query(k, node[old].r, node[cur].r, mid + 1, R);
}else {
return node[node[cur].r].sum - node[node[old].r].sum
+ query(k-tmp, node[old].l, node[cur].l, L, mid);
}
}*/
int main(){
scanf("%d%d", &n, &q);
for(int i = 1; i <= n; ++i) scanf("%d", ar+i), sum[i]=sum[i-1]+ar[i];
for(int i = 1; i <= q; ++i) {
scanf("%d%d%d", &cw[i].l, &cw[i].r, &cw[i].k);
cw[i].ans = sum[cw[i].r] - sum[cw[i].l-1];
}
LL L, R;
for(int T = 30; T >= 0; --T) {
L = 1LL<<T, R = 2LL<<T, inde = 0;
node[0].l = node[0].r = node[0].sum = node[0].cnt = 0;
for(int i = 1; i <= n; ++i) if(ar[i]>>T&1) {
z_update(Root[i-1], Root[i], ar[i], L, R);
//if(T == 2) printf("[%d %d]\n", i, ar[i]);
sum[i] = sum[i-1] + ar[i] - ar[i]/2; num[i] = num[i-1] + 1;
}else Root[i] = Root[i-1], sum[i] = sum[i-1], num[i] = num[i-1];
//printf("T = %d\n", T);
for(int i = 1, tmp; i <= q; ++i) {
if(cw[i].k == 0) continue;
if(cw[i].k >= num[cw[i].r] - num[cw[i].l-1]) {
cw[i].k -= num[cw[i].r] - num[cw[i].l-1];
cw[i].ans -= sum[cw[i].r] - sum[cw[i].l-1];
}else {
//printf("*%lld %d ", cw[i].ans, cw[i].k);
cw[i].ans -= z_query(cw[i].k, Root[cw[i].l-1], Root[cw[i].r], L, R);
//printf("%lld %d\n", cw[i].ans, T);
cw[i].k = 0;
}
//printf("%d %d %d\n", cw[i].l, cw[i].r, cw[i].k);
}
for(int i = 1; i <= n; ++i) if(ar[i]>>T&1) ar[i] >>= 1;
//printf("***\n");
}
for(int i = 1; i <= q; ++i) printf("%lld\n", cw[i].ans);
return 0;
}
5E div1 Fast Kronecker Transform (NTTorFFT)
//E
题解就在这个博客里
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
namespace lh {
#define o2(x) (x)*(x)
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int, LL> pii;
}
using namespace lh;
const int MX = 2e5 + 5;
//const int P = (479 << 21) + 1;
const int P = 998244353;
const int MOD = 998244353;
const int G = 3;
const int NUM = 20;
struct my_NTT {
LL wn[NUM];
LL a[MX << 1], b[MX << 1];
LL pow (LL a, LL x, LL mod) {
LL ans = 1;
a %= mod;
while (x) {
if (x & 1) ans = ans * a % mod;
x >>= 1;
a = a * a % mod;
}
return ans;
}
//在程序的开头就要放
void init() {
for (int i = 0; i < NUM; i++) {
int t = 1 << i;
wn[i] = pow (G, (P - 1) / t, P);
}
}
void Rader (LL F[], int len) {
int j = len >> 1;
for (int i = 1; i < len - 1; i++) {
if (i < j) swap (F[i], F[j]);
int k = len >> 1;
while (j >= k) j -= k, k >>= 1;
if (j < k) j += k;
}
}
void NTT (LL F[], int len, int t) {
Rader (F, len);
int id = 0;
for (int h = 2; h <= len; h <<= 1) {
id++;
for (int j = 0; j < len; j += h) {
LL E = 1;
for (int k = j; k < j + h / 2; k++) {
LL u = F[k];
LL v = E * F[k + h / 2] % P;
F[k] = (u + v) % P;
F[k + h / 2] = (u - v + P) % P;
E = E * wn[id] % P;
}
}
}
if (t == -1) {
for (int i = 1; i < len / 2; i++) swap (F[i], F[len - i]);
LL inv = pow (len, P - 2, P);
for (int i = 0; i < len; i++) F[i] = F[i] * inv % P;
}
}
void Conv (LL a[], LL b[], int len) {
NTT (a, len, 1);
NTT (b, len, 1);
for (int i = 0; i < len; i++) a[i] = a[i] * b[i] % P;
NTT (a, len, -1);
}
int gao (LL A[], LL B[], int n, int m, LL ans[]) {//0~n-1
int len = 1;
while (len < n + m) len <<= 1;
for (int i = 0; i < n; i++) a[i] = A[i];
for (int i = 0; i < m; i++) b[i] = B[i];
for (int i = n; i < len; i++) a[i] = 0;
for (int i = m; i < len; i++) b[i] = 0;
Conv (a, b, len);
for (int i = 0; i < len; i++) ans[i] = (ans[i]+a[i])%MOD;
return len;
}
}ntt;
const int MXN = 2e5 + 5;
int n, m;
int ar[MXN], br[MXN];
LL A[MXN], B[MXN];
std::vector<int> all[MXN], bll[MXN];
LL ans[MXN];
void solve1(int id) {
for(int i = 0; i < all[id].size(); ++i) {
for(int j = 0; j < bll[id].size(); ++j) {
ans[all[id][i]+bll[id][j]] += (LL)all[id][i] * bll[id][j];
ans[all[id][i]+bll[id][j]] %= MOD;
}
}
}
void solve2(int id) {
for(int i = 0; i <= n+m; ++i) A[i] = B[i] = 0;
for(int i = 0; i < all[id].size(); ++i) A[all[id][i]] = all[id][i];
for(int i = 0; i < bll[id].size(); ++i) B[bll[id][i]] = bll[id][i];
int len = ntt.gao(A, B, all[id].back()+1, bll[id].back()+1, ans);
}
int main(int argc, char const *argv[]) {
scanf("%d%d", &n, &m); ++n, ++m;
ntt.init();
std::vector<int> vs;
for(int i = 0; i < n; ++i) scanf("%d", &ar[i]), vs.push_back(ar[i]);
for(int i = 0; i < m; ++i) scanf("%d", &br[i]), vs.push_back(br[i]);
sort(vs.begin(), vs.end());
vs.erase(unique(vs.begin(), vs.end()), vs.end());
for(int i = 0, tmp; i < n; ++i) {
tmp = lower_bound(vs.begin(), vs.end(), ar[i]) - vs.begin();
all[tmp].push_back(i);
}
for(int i = 0, tmp; i < m; ++i) {
tmp = lower_bound(vs.begin(), vs.end(), br[i]) - vs.begin();
bll[tmp].push_back(i);
}
for(int i = 0; i < vs.size(); ++i) {
if(all[i].size() + bll[i].size() <= 10000) solve1(i);
else solve2(i);
}
for(int i = 0; i <= n + m-2; ++i) printf(i!=n+m-2?"%lld ":"%lld\n", ans[i]);
return 0;
}
day7
7G div1&2 抢红包机器人 (拓扑序)
//G
#include<bits/stdc++.h>
#define fi first
#define se second
#define iis std::ios::sync_with_stdio(false)
#define pb push_back
#define o2(x) (x)*(x)
using namespace std;
typedef long long LL;
typedef pair<int, LL> pii;
const int MXN = 2e2 + 6;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
int n, m;
int ar[MXN][MXN], pos[MXN][MXN];
int vis[MXN], far[MXN], is[MXN], id[MXN];
int flag;
std::vector<int> mp[MXN];
void dfs(int u,int ba) {
vis[u] = 1;
flag ++;
for(auto v: mp[u]) {
if(vis[v]) continue;
dfs(v, u);
}
}
int main(){
scanf("%d%d", &n, &m);
queue<int> Q;
for(int i = 1, k; i <= m; ++i) {
scanf("%d", &k);
ar[i][0] = k;
for(int j = 1, x; j <= k; ++j) {
scanf("%d", &ar[i][j]);
is[ar[i][j]] = 1;
}
}
int cnt = INF;
for(int i = 1; i <= m; ++i) {
for(int j = 2; j <= ar[i][0]; ++j) {
mp[ar[i][j]].push_back(ar[i][j-1]);
}
}
for(int i = 1; i <= n; ++i) {
flag = 0;
memset(vis, 0, sizeof(vis));
dfs(i, i);
cnt = min(cnt, flag);
}
printf("%d\n", cnt);
return 0;
}
7A div1 迷宫 (树 规律)
//A
#include<bits/stdc++.h>
#define fi first
#define se second
#define iis std::ios::sync_with_stdio(false)
#define pb push_back
#define o2(x) (x)*(x)
using namespace std;
typedef long long LL;
typedef pair<int, LL> pii;
const int MXN = 2e5 + 6;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
int n, m;
std::vector<int> mp[MXN];
int is[MXN], dep[MXN],dp[MXN], ans;
void dfs(int u,int ba,int d) {
int sum = 0;
if(is[u]) dep[d] ++;
m = max(m, d);
for(auto v: mp[u]) {
if(v == ba) continue;
dfs(v, u, d + 1);
}
}
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; ++i) scanf("%d", &is[i]);
for(int i = 1, a, b; i < n; ++i) {
scanf("%d%d", &a, &b);
mp[a].push_back(b);
mp[b].push_back(a);
}
dfs(1, 1, 0);
for(int i = 1; i <= 2*n; ++i) {
//ans += max(dep[i]-1,0);
if(dep[i] >= 2) {
dep[i+1] += dep[i]-1;
}
if(dep[i]) ans = i;
}
printf("%d\n", ans);
return 0;
}
7E div2 线性探查法 (暴力)
//E
#include<bits/stdc++.h>
#define fi first
#define se second
#define iis std::ios::sync_with_stdio(false)
#define pb push_back
#define o2(x) (x)*(x)
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MXN = 2e3 + 6;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
int n, m;
int ar[MXN], br[MXN], ans[MXN], is[MXN];
int main(){
scanf("%d", &n);
std::vector<pii> dai;
for(int i = 0; i < n; ++i) scanf("%d", &br[i]), dai.push_back({br[i],i});
memset(ans, -1, sizeof(ans));
int cnt = 1;
while(cnt <= n) {
int MMIN = INF, pos = -1, ers;
//printf("cnt = %d\n", cnt);
for(int i = 0; i < dai.size(); ++i) {
int tmp = dai[i].fi % n;
while(ans[tmp] != -1) {
tmp = (tmp + 1) % n;
}
//printf("*%d %d %d\n", dai[i].fi, tmp, dai[i].se);
if(tmp == dai[i].se) {
if(MMIN > dai[i].fi) {
MMIN = dai[i].fi;
pos = tmp;
ers = i;
}
}
}
//printf("--%d %d\n", MMIN, pos);
if(cnt != n) printf("%d ", MMIN);
else {
printf("%d\n", MMIN);
break;
}
ans[pos] = MMIN;
for(int i = ers; i < dai.size() - 1; ++i) {
dai[i] = dai[i+1];
}
dai.resize(dai.size()-1);
cnt ++;
}
return 0;
}
7C div1 斐波那契数列 (打表找规律)
//C
#include<bits/stdc++.h>
#define fi first
#define se second
#define iis std::ios::sync_with_stdio(false)
#define pb push_back
#define o2(x) (x)*(x)
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MXN = 2e5 + 6;
const int INF = 0x3f3f3f3f;
const LL mod = 998244353;
LL n, m;
typedef vector<long long> vec;
typedef vector<vec > mat;
mat Mul(mat a, mat b) {
mat c(a.size(), vec(b[0].size()));
for(int k = 0; k < b.size(); ++k) {
for(int i = 0; i < a.size(); ++i) {
if(a[i][k] == 0) continue;
for(int j = 0; j < b[0].size(); ++j) {
c[i][j] = (c[i][j] + a[i][k] * b[k][j])%mod;
}
}
}
return c;
}
mat mat_ksm(mat a, LL b) {
mat res(a.size(), vec(a.size()));
for(int i = 0; i < a.size(); ++i) res[i][i] = 1;
while(b) {
if(b&1) res = Mul(res, a);
a = Mul(a, a);
b >>= 1;
}
return res;
}
LL fib_n(LL n) {
mat a(2, vec(2));
a[0][0] = 1; a[0][1] = 1;
a[1][0] = 1; a[1][1] = 0;
a = mat_ksm(a, n);
return a[1][0];
}
LL getnum(LL n) {
LL ans = n - n/3, now = 2;
n /= 3;
while(n) {
ans = (ans + (n+1)/2*now%mod)%mod;
n /= 2;
if(now == 2) now = 8;
else now = now*2%mod;
}
return ans;
}
int main(){
int tim; scanf("%d", &tim);
while(tim --) {
scanf("%lld", &n);
if(n <= 2) {
printf("0\n");
continue;
}
LL ans = (fib_n(n+2) - 1 + mod)%mod;
printf("%lld\n", (ans - getnum(n) + mod)%mod);
}
return 0;
}
7F div2 逆序对! (规律)
//F
//假设a > b且a^b的最高位是第i位, 则a^s > b^s的条件是s的第i位为0.
#include<bits/stdc++.h>
#define fi first
#define se second
#define iis std::ios::sync_with_stdio(false)
#define pb push_back
#define o2(x) (x)*(x)
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MXN = 1e5 + 6;
const int INF = 0x3f3f3f3f;
const LL mod = 998244353;
int n, m;
LL ar[MXN];
LL dp[55][2][55][2];
LL two[55], my[55][2], num[55];
std::vector<int> vs;
int solve(int tn) {
while(tn) {
vs.push_back(tn&1);
tn >>= 1;
}
int cnt = 1;
LL T = 1;
for(auto x: vs) {
num[cnt] = num[cnt-1]+T*x;
++ cnt; T *= 2;
}
reverse(vs.begin(), vs.end());
LL zhi = vs[0];
int len = vs.size();
my[1][0] = (two[len-1] - 1 + mod) % mod;
my[1][1] = m - (1LL<<(len-1)) + 1;
assert(my[1][0]+my[1][1] == m);
for(int i = 1; i < len; ++i) {
if(vs[i]) {
my[i+1][1] = num[len-i-1] + 1 + (zhi)*two[len-i-1];
my[i+1][0] = (zhi+1)*two[len-i-1] - 1;
}else {
my[i+1][1] = (zhi)*two[len-i-1];
my[i+1][0] = num[len-i-1] + 1 + (zhi)*two[len-i-1] - 1;
}
my[i+1][1] = (my[i+1][1]%mod + mod)%mod;
my[i+1][0] = (my[i+1][0]%mod + mod)%mod;
assert(my[i][0]+my[i][1] == m);
zhi = zhi * 2 + vs[i];
}
return len;
}
int get(LL NUM) {
int x = 0;
while(NUM) {
++ x;
NUM /= 2;
}
return x;
}
int main(){
scanf("%d%d", &n, &m);
two[0] = 1; for(int i = 1; i <= 32; ++i) two[i] = two[i-1] * 2 % mod;
int len = solve(m);
for(int i = 1; i <= n; ++i) scanf("%lld", &ar[i]);
if(n == 1) {printf("0\n");return 0;}
LL ANS = 0, temp;
for(int i = 1; i < n; ++i) {
for(int j = i + 1; j <= n; ++j) {
int tmp = get(ar[i]^ar[j]); temp = 0;
if(ar[i] > ar[j]) {
if(tmp > len) temp = m;
else temp = my[len-tmp+1][0];
}else {
if(tmp <= len) temp = my[len-tmp+1][1];
}
ANS = (ANS + temp + mod)%mod;
}
}
printf("%lld\n", ANS%mod);
return 0;
}
这个题也可以跑数位dp,比如这样:
LL solve(int id, int ip, int pos, int pre, bool zero, bool limit) {//第id位必须为ip的方案数
if(pos == -1) {
if(zero) return 0;
return 1;
}
if(!limit&&!zero&&dp[id][ip][pos][pre]!=-1) return dp[id][ip][pos][pre];
int up = limit?num[pos]:1, low = 0;
LL sum = 0;
if(pos == id) {
if(limit && num[pos] == 0 && ip == 1) return 0;
up = low = ip;
}
for(int i = low; i <= up; ++i) {
sum += solve(id, ip, pos-1, i, zero&&i==0,limit&&i==num[pos]);
}
if(!limit&&!zero) dp[id][ip][pos][pre] = sum;
return sum;
}
7J div1&2 强壮的排列
/*
题意:
T(1e4),n(1e5)奇数
问有多少个长度为n的排列满足一下条件:
(1<=x<=n/2) p[2*x]=max(p[2*x-1],p[2*x+1])
题解:
https://www.90yang.com/category/algorithm/
https://blog.csdn.net/nike0good/article/details/86662644
*/
//oeis解法
//n%4==0和n=1时Bnl[n]是负的
//a(n) = abs[c(2*n-1)] where c(n)= 2^(n+1) * (1-2^(n+1)) * Ber(n+1)/(n+1)
//a(n) = 2^(2*n) (2^(2*n) - 1) |B_(2*n)|
#include<bits/stdc++.h>
#pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
const int mod = 998244353;
namespace BNL{
using namespace std;
const int N = 300020;
//const LL P = 50000000001507329LL; //190734863287 * 2 ^ 18 + 1 G = 3 常数巨大
//const int P = 1004535809; //479 * 2 ^ 21 + 1 G = 3
const int P = 998244353; // 119 * 2 ^ 23 + 1 G = 3
//const int P = 104857601; // 25 * 2 ^ 22 + 1 G = 3
//const int P = 167772161; // 5 * 2 ^ 25 + 1 G = 3
const int G = 3;
int wn[25];
LL mul(LL x, LL y) {return (x * y - (LL)(x / (long double)P * y + 1e-3) * P + P) % P;}
LL qpow(LL a, int b, int mod=P) {
LL res = 1;
for(;b;b>>=1,a=a*a%mod) {
if(b&1) res=res*a%mod;
}
return res;
}
void getwn() {
for(int i = 1; i <= 21; ++i) {
int t = 1 << i;
wn[i] = qpow(G, (P - 1) / t, P);
}
}
void change(int *y, int len) {
for(int i = 1, j = len / 2; i < len - 1; ++i) {
if(i < j) swap(y[i], y[j]);
int k = len / 2;
while(j >= k) {
j -= k;k /= 2;
}
j += k;
}
}
void NTT(int *y, int len, int on) {
change(y, len);
int id = 0;
for(int h = 2; h <= len; h <<= 1) {
++id;
for(int j = 0; j < len; j += h) {
int w = 1;
for(int k = j; k < j + h / 2; ++k) {
int u = y[k];
int t = 1LL * y[k+h/2] * w % P;
y[k] = u + t;
if(y[k] >= P) y[k] -= P;
y[k+h/2] = u - t + P;
if(y[k+h/2] >= P) y[k+h/2] -= P;
w = 1LL * w * wn[id] % P;
}
}
}
if(on == -1) {
for(int i = 1; i < len / 2; ++i) swap(y[i], y[len-i]);
int inv = qpow(len, P - 2, P);
for(int i = 0; i < len; ++i)
y[i] = 1LL * y[i] * inv % P;
}
}
int tmp[N];
void get_inv(int A[], int A0[], int t) {
if(t == 1) {
A0[0] = qpow(A[0], P - 2, P);
return;
}
get_inv(A, A0, t / 2);
for(int i = 0; i < t; ++i) tmp[i] = A[i];
for(int i = t; i < 2 * t; ++i) tmp[i] = 0;
for(int i = t / 2; i < 2 * t; ++i) A0[i] = 0;
NTT(tmp, 2 * t, 1);
NTT(A0, 2 * t, 1);
for(int i = 0; i < 2 * t; ++i) {
tmp[i] = (2 - 1LL * tmp[i] * A0[i] % P) % P;
if(tmp[i] < 0) tmp[i] += P;
A0[i] = 1LL * A0[i] * tmp[i] % P;
}
NTT(A0, 2 * t, -1);
}
int B[N], f[N], nf[N], a[N];
void init() {
f[0] = 1;
for(int i = 1; i < N; ++i) f[i] = 1LL * f[i-1] * i % P;
nf[N-1] = qpow(f[N-1], P - 2, P);
for(int i = N - 2; i >= 0; --i) {
nf[i] = 1LL * nf[i+1] * (i + 1) % P;
}
for(int i = 0; i < N - 1; ++i) a[i] = nf[i+1];
int len = 1 << 17;
get_inv(a, B, len);
for(int i = 0; i < len; ++i) B[i] = 1LL * B[i] * f[i] % P;
}
void solve_bnl() {
getwn();//最前面
init();
}
}
using namespace BNL;
LL solve(int n) {
return 1LL*(1-qpow(2,n+1))%mod*qpow(2,n+1)%mod*B[n+1]%mod*qpow(n+1,mod-2)%mod;
}
int main() {
solve_bnl();
for(int i = 0; i <= 20; ++i) printf("%d\n", B[i]);
int tim; scanf("%d", &tim);
while(tim --) {//n为奇数,1,3,5...
int n; scanf("%d", &n); n = (n+1)/2;
n = 2*n-1;
LL ans = (solve(n)+mod)%mod;
if(n+1 >= 1)ans = (mod-ans)%mod;
if((n+1)%4==0 || n+1==1) ans = (mod-ans);
printf("%lld\n", ans);
}
return 0;
}
7H div2 同构 整数划分
#include<bits/stdc++.h>
#define fi first
#define se second
#define iis std::ios::sync_with_stdio(false)
#define eb emplace_back
#define o2(x) (x)*(x)
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int mod = 998244353;
int n;
LL dp[1005][1005];
LL q(int n,int m){
if(dp[n][m] != -1) return dp[n][m];
if(n == 3) return 1;
else if(n < 3) return 0;
if(m < 3) return 0;
LL sum = 0;
if(n < m) sum = q(n,n);
if(n == m) sum = q(n,m-1)+1;
if(n>m) sum = (q(n,m-1) + q(n-m,m))%mod;
dp[n][m] = sum;
return dp[n][m];
}
int main(){
memset(dp, -1, sizeof(dp));
scanf("%d",&n);
if(n <= 5) {
printf("1\n");
}else printf("%lld\n",q(n,n)%mod);
return 0;
}
7H div1 同构 整数划分
五边形数
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 8;
const int mo = 998244353;
typedef long long LL;
LL dp[N];
int main(){
int n = 1e5+1;
dp[0] = 1;
for (int i = 1; i <= n; ++i){
for (LL j = 1, tmp = 1; i >= (3 * j * j - j) / 2; ++j, tmp *= -1){
LL x = (3 * j * j - j) / 2;
LL y = (3 * j * j + j) / 2;
dp[i] = ((dp[i] + tmp * dp[i - x]) % mo + mo) % mo;
if (i >= y) dp[i] = ((dp[i] + tmp * dp[i - y]) % mo + mo) % mo;
}
}
scanf("%d", &n);
if(n < 3) printf("0\n");
else if(n == 3) printf("1\n");
else printf("%lld\n", ((((dp[n]-dp[n-1])%mo-dp[n-2])%mo+dp[n-3])%mo+mo)%mo);
return 0;
}
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int mul(int a, int b, int mod){ return (long long)a*b%mod; }
int power(int a, int b, int mod){
int ret = 1;
for (int t = a; b; b >>= 1){
if (b & 1)ret = mul(ret, t, mod);
t = mul(t, t, mod);
}
return ret;
}
int cal_root(int mod)
{
int factor[20], num = 0, m = mod - 1, s = m;
for (int i = 2; i * i <= s; i++){
if (s % i == 0){
factor[num++] = i;
while (s % i == 0)s /= i;
}
}
if (s != 1)factor[num++] = s;
for (int i = 2;; i++){
int j = 0;
for (; j < num && power(i, m / factor[j], mod) != 1; j++);
if (j == num)return i;
}
}
template<int MOD, int ROOT>
void fft_main(int a[], int len, bool reverse)
{
for (int i = 1, j = len / 2; i < len - 1; i++) {
if (i < j) swap(a[i], a[j]);
for (int k = len; j < k; k >>= 1, j ^= k);
}
for (int s = 1; s < len; s <<= 1){
int t = (MOD - 1) / (s * 2);
int step = power(ROOT, reverse ? MOD - 1 - t : t, MOD);
for (int j = 0; j < len; j += 2 * s){
int cur = 1;
for (int k = j; k < j + s; k++){
int u = a[k], t = mul(cur, a[k + s], MOD);
a[k] = (unsigned int)(u + t) % MOD;
a[k + s] = (unsigned int)(u - t + MOD) % MOD;
cur = mul(cur, step, MOD);
}
}
}
if (reverse){
int t = power(len, MOD - 2, MOD);
for (int i = 0; i < len; i++)
a[i] = mul(a[i], t, MOD);
}
}
//确保数组中的数小于mod(mod<2^30),数组需留足2^(logn向上取整+1)的空间
//并且mod为形如m*2^k+1的素数,2^k>=2*n
template<int MOD, int ROOT>
void fft(int a[], int b[], int n){
int len = 1;
while (len < 2 * n)len <<= 1;
memset(a + n, 0, sizeof(int)*(len - n));
memset(b + n, 0, sizeof(int)*(len - n));
fft_main<MOD, ROOT>(a, len, 0);
fft_main<MOD, ROOT>(b, len, 0);
for (int i = 0; i < len; i++)
a[i] = mul(a[i], b[i], MOD);
fft_main<MOD, ROOT>(a, len, 1);
}
#define MAXN 131072
int par[2*MAXN];
int dp2[2*MAXN],dp[350][MAXN];
template<int MOD, int ROOT>
void calParNumber(int n){
int s=sqrt(n)+1;
par[0]=1;
for(int i=3;i<s;i++){
for(int j=i;j<=n;j++)
(par[j]+=par[j-i])%=MOD;
}
dp[0][0]=1;dp2[0]=1;
for(int i=1;i<=s;i++){
for(int j=s;j<=n;j++){
dp[i][j]=(dp[i-1][j-s]+dp[i][j-i])%MOD;
(dp2[j]+=dp[i][j])%=MOD;
}
}
fft<MOD,ROOT>(par,dp2,n+1);
}
int main(){
calParNumber<998244353,3>(100000);
int n;
scanf("%d",&n);
printf("%d",par[n]);
}
day8
8G div1&2 穗乃果的考试 (计数)
//div1G
题解:https://blog.csdn.net/qq_39599067/article/details/86713379
#include<bits/stdc++.h>
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
typedef long long LL;
const int MXN = 2e3 + 7;
const LL mod = 998244353;
int n, m;
int ar[MXN][MXN];
LL sum[MXN][MXN], sum1[MXN][MXN], sum2[MXN][MXN], sum3[MXN][MXN],sum4[MXN][MXN];
LL up[MXN][MXN], Left[MXN][MXN], Right[MXN][MXN], down[MXN][MXN];
char s[MXN];
int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i) {
scanf("%s", s+1);
for(int j = 1; j <= m; ++j) ar[i][j] = s[j] - '0';
}
for(int i = 1; i <= n; ++i) {
for(int j = 1, tmp; j <= m; ++j) {
if(ar[i][j] == 0) tmp = 0;else tmp = i*j;
sum[i][j] = sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+tmp;
sum[i][j] = (sum[i][j]%mod+mod)%mod;
}
}
for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) sum1[i][j] = sum[i-1][j-1];
memset(sum, 0, sizeof(sum));
for(int i = 1; i <= n; ++i) {
for(int j = m, tmp; j >= 1; --j) {
if(ar[i][j] == 0) tmp = 0;else tmp = i*(m-j+1);
sum[i][j] = sum[i-1][j]+sum[i][j+1]-sum[i-1][j+1]+tmp;
sum[i][j] = (sum[i][j]%mod+mod)%mod;
}
}
for(int i = 1; i <= n; ++i) for(int j = m; j >= 1; --j) sum2[i][j] = sum[i-1][j+1];
memset(sum, 0, sizeof(sum));
for(int i = n; i >= 1; --i) {
for(int j = 1, tmp; j <= m; ++j) {
if(ar[i][j] == 0) tmp = 0;else tmp = (n-i+1)*j;
sum[i][j] = sum[i+1][j]+sum[i][j-1]-sum[i+1][j-1]+tmp;
sum[i][j] = (sum[i][j]%mod+mod)%mod;
}
}
for(int i = n; i >= 1; --i) for(int j = 1; j <= m; ++j) sum3[i][j] = sum[i+1][j-1];
memset(sum, 0, sizeof(sum));
for(int i = n; i >= 1; --i) {
for(int j = m, tmp; j >= 1; --j) {
if(ar[i][j] == 0) tmp = 0;else tmp = (n-i+1)*(m-j+1);
sum[i][j] = sum[i+1][j]+sum[i][j+1]-sum[i+1][j+1]+tmp;
sum[i][j] = (sum[i][j]%mod+mod)%mod;
}
}
for(int i = n; i >= 1; --i) for(int j = m; j >= 1; --j) sum4[i][j] = sum[i+1][j+1];
for(int i = 2; i <= n; ++i) {
for(int j = 1, tmp; j <= m; ++j) {
if(ar[i-1][j] == 0) tmp = 0; else tmp = (i-1)*j;
up[i][j] = up[i-1][j] + tmp;
up[i][j] %= mod;
}
}
for(int i = 1; i <= n; ++i) {
for(int j = 2, tmp; j <= m; ++j) {
if(ar[i][j-1] == 0) tmp = 0; else tmp = i*(j-1);
Left[i][j] = Left[i][j-1] + tmp;
Left[i][j] %= mod;
}
}
for(int i = 1; i <= n; ++i) {
for(int j = m - 1, tmp; j >= 1; --j) {
if(ar[i][j+1] == 0) tmp = 0; else tmp = (n-i+1)*(m-j);
Right[i][j] = Right[i][j+1] + tmp;
Right[i][j] %= mod;
}
}
for(int i = n-1; i >= 1; --i) {
for(int j = 1, tmp; j <= m; ++j) {
if(ar[i+1][j] == 0) tmp = 0; else tmp = (n-i)*(m-j+1);
down[i][j] = down[i+1][j] + tmp;
down[i][j] %= mod;
}
}
LL ans = 0;
for(LL i = 1; i <= n; ++i) {
for(LL j = 1; j <= m; ++j) {
if(ar[i][j] == 0) continue;
ans = (ans + i*j%mod*(n-i+1)%mod*(m-j+1)%mod) % mod;
ans = (ans + (sum1[i][j]+up[i][j]+Left[i][j])%mod*(n-i+1)%mod*(m-j+1)%mod)%mod;
ans = (ans + (Right[i][j]+down[i][j]+sum4[i][j])%mod*i%mod*j%mod)%mod;
ans = (ans + sum2[i][j]*(n-i+1)%mod*j%mod+sum3[i][j]*(m-j+1)%mod*i%mod)%mod;
}
}
printf("%lld\n", (ans+mod)%mod);
return 0;
}
//div2G
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int INF = 0x3f3f3f3f;
const int MXN = 1e6 + 6;
const LL mod = 998244353;
LL san[33];
LL dp[44][44][3][44];
int ar[2005][2005];
char s[2005];
LL o2(LL x, LL y) {
return (x*(x+1)/2)*(y*(y+1)/2)%mod;
}
int main() {
LL n, m;
scanf("%lld%lld", &n, &m);
LL ans = 0;
for(LL i = 1; i <= n; ++i) {
scanf("%s", s+1);
for(LL j = 1; j <= m; ++j) {
int x = s[j]-'0';
if(x == 0) continue;
ans += o2(n,m) - o2((i-1),m) - o2((n-i),m) - o2((j-1),n) - o2((m-j),n);
ans += o2((i-1),(j-1))+o2((i-1),(m-j))+o2((n-i),(j-1))+o2((n-i),(m-j));
ans = (ans % mod + mod) % mod;
}
}
printf("%lld\n", ans);
return 0;
}
8D div2 吉良吉影的奇妙计划 (dp)
//D
#include<bits/stdc++.h>
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
typedef long long LL;
const int MXN = 4e1 + 7;
const LL mod = 998244353;
int n, m;
LL dp[MXN][MXN][MXN][3];
int main() {
scanf("%d", &n); n <<= 1;
dp[1][1][0][1] = 1;
dp[1][0][1][2] = 1;
dp[2][1][1][0] = 1;
for(int i = 1; i <= n; ++i) {
for(int x = 0; x <= i; ++x) {
for(int y = 0; y + x <= i; ++y) {
dp[i+2][x+1][y+1][0] = (dp[i][x][y][1] + dp[i][x][y][2])%mod;
dp[i+1][x+1][y][1] = (dp[i][x][y][1] + dp[i][x][y][0])%mod;
dp[i+1][x][y+1][2] = (dp[i][x][y][2] + dp[i][x][y][0])%mod;
}
}
}
LL ans = (dp[n][n/2][n/2][0]+dp[n][n/2][n/2][1]+dp[n][n/2][n/2][2]) % mod;
printf("%lld\n", ans);
return 0;
}
/*
id = 0表示空白
id = 1表示左
id = 2表示右
dp[i][x][y][id]到第i天选了x个左y个右最后一个是id的方案数
人人为我:
dp[i][x][y][0] = dp[i-2][x-1][y-1][1] + dp[i-2][x-1][y-1][2];
dp[i][x][y][1] = dp[i-1][x-1][y][1] + dp[i-1][x-1][y][2] + dp[i-1][x-1][y][0];
dp[i][x][y][2] = dp[i-1][x][y-1][2] + dp[i-1][x][y-1][0];
我为人人:
dp[i+2][x+1][y+1][0] = dp[i][x][y][1] + dp[i][x][y][2];
dp[i+1][x+1][y][1] = dp[i][x][y][1] + dp[i][x][y][2] + dp[i][x][y][0];
dp[i+1][x][y+1][2] = dp[i][x][y][2] + dp[i][x][y][0];
*/
8A div1 Aqours (性质 dp)
//A
#include<bits/stdc++.h>
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
typedef long long LL;
const int MX = 4e6 + 7;
int n;
vector<int> cw[MX];
vector<int> vs;
int vis[MX];
int mp[MX];
int D, ANS;
inline int upup(int u, int d) {
if(vis[u]) {ANS = d + vis[u];return vis[u];}
vis[u] = d;
int T = upup(mp[u], d+1);
vis[u] = min(vis[u], T + 1);
return vis[u];
}
int main() {
scanf("%d", &n);
if(n == 1) {
printf("1 -1\n");
return 0;
}
for(int i = 2, u; i <= n; ++i) {
scanf("%d", &u);
cw[u].push_back(i);
mp[i] = u;
}
for(int i = 1;i <= n;i++) if(cw[i].size() == 0) vs.push_back(i);
sort(vs.begin(), vs.end());
printf("%d -1\n", vs[0]);
vis[0] = 1e8;
upup(vs[0], 0);
for(int i = 1; i < vs.size(); ++i) {
upup(vs[i], 0);
printf("%d %d\n", vs[i], ANS);
//io.wint(vs[i],0);io.wint(len+D,1);
}
return 0;
}
8B div1 玖凛两开花 (匈牙利+枚举or二分)
#include<bits/stdc++.h>
#define clr(a, b) memset(a,b,sizeof((a)))
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
typedef long long LL;
const int MXN = 2e4 + 7;
const LL mod = 998244353;
int n, m;
struct lp {
int u, v;
}cw[MXN];
std::vector<int> son[MXN];
int vis[MXN], be[MXN], is[MXN];
int L;
bool dfs(int u){
for(auto x : son[u]){
if(x < L) continue;
if(vis[x]) continue;
vis[x] = 1;
if(is[x] == -1 || dfs(is[x])){
is[x] = u;
be[u] = x;
return true;
}
}
return false;
}
int main() {
scanf("%d%d", &n, &m);
for(int i = 0; i < m; ++i) {
scanf("%d%d", &cw[i].u, &cw[i].v);
cw[i].u++; cw[i].v++;
if(cw[i].u > cw[i].v) swap(cw[i].u, cw[i].v);
son[cw[i].u].push_back(cw[i].v);
}
for(int i = 1; i <= n; ++i) is[i] = be[i] = -1;
int ans = 1;
for(int i = 1; i <= n; ++i) {
L = i + 1;
if(is[i] != -1) {
for(int j = 1; j <= n; ++j) vis[j] = 0;
if(!dfs(is[i])) break;
is[i] = -1;
}
for(int j = 1; j <= n; ++j) vis[j] = 0;
if(dfs(i)) ++ ans;
else break;
}
printf("%d\n", ans - 1);
return 0;
}
/*
考虑二分答案是否>= x,可以把图变成一个二分图,左边是< x的,右边是>= x的。在原图中两部分
内部是可能有边的,但是选出这些边不会对“答案能达到x”更有利,所以这些边忽略即可。然后可以用匈
牙利算法检查是否左边的点是否全部都能匹配上。时间复杂度O(nmlogn),因为匈牙利算法很难卡到上
限O(nm)且常数很小,所以也能通过。
实际上二分答案的过程可以去掉。我们考虑把二分的过程变成从小到大枚举,到x + 1的时候就是把x点
加入二分图的左边。如果x之前在右边的时候和某个左边的点v匹配过了,把这个匹配关系拆掉,把v再
匹配一遍就可以了。时间复杂度O(nm)。
如果用Dinic或者HK的话,时间复杂度可以做到O(m√n)。
*/
//二分+dinic
#include<bits/stdc++.h>
#define clr(a, b) memset(a,b,sizeof((a)))
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
typedef long long LL;
const int MXAN = 2e4 + 7;
const LL mod = 998244353;
int n, m;
struct lp {
int u, v;
}cw[MXAN];
const int INF = 0x3f3f3f3f;
const int MXN = 1e4+7;
const int MXE = 1e6+7;
struct DINIC{
int tot,vt,vs;
int d[MXN],head[MXN];
struct lp{
int v,w,nex;
}cw[MXE];
void add_edge(int a,int b,int c){
cw[++tot].v=b;cw[tot].nex=head[a],cw[tot].w=c;
head[a]=tot;
cw[++tot].v=a;cw[tot].nex=head[b],cw[tot].w=0;
head[b]=tot;
}
bool bfs(){
memset(d,-1,sizeof(d));
queue<int>Q;
Q.push(vt);d[vt]=0;
while(!Q.empty()){
int u=Q.front();
Q.pop();
for(int i=head[u];i!=-1;i=cw[i].nex){
int v=cw[i].v;
if(cw[i^1].w&&d[v]==-1){
d[v]=d[u]+1;
Q.push(v);
}
}
}
return d[vs]!=-1;
}
int dfs(int x,int low){
if(x==vt||low==0)return low;
int flow=0,used=0;
for(int i=head[x];i!=-1;i=cw[i].nex){
int v=cw[i].v;
if(cw[i].w&&d[v]+1==d[x]&&(used=dfs(v,min(low,cw[i].w)))>0){
//used=dfs(v,min(low,cw[i].w));
if(!used)continue;
flow+=used,low-=used;
cw[i].w-=used;cw[i^1].w+=used;
if(!low)break;
}
}
if(!flow)d[x]=-1;
return flow;
}
void init(int st,int ed){
tot=-1;
for(int i = st; i <= ed; ++i) head[i] = -1;
vs=st;vt=ed;
}
int max_flow(){
int ans=0;
while(bfs())ans+=dfs(vs,INF);
return ans;
}
}dinic;
int vs, vt;
bool ok(int mid) {
vs = 0, vt = n + 1;
dinic.init(vs, vt);
for(int i = 1; i < mid; ++i) dinic.add_edge(vs, i, 1);
for(int i = mid; i <= n; ++i) dinic.add_edge(i, vt, 1);
for(int i = 0; i < m; ++i) {
if(cw[i].v >= mid && cw[i].u < mid) {
dinic.add_edge(cw[i].u, cw[i].v, 1);
}
}
return dinic.max_flow() == mid-1;
}
int main() {
scanf("%d%d", &n, &m);
for(int i = 0; i < m; ++i) {
scanf("%d%d", &cw[i].u, &cw[i].v);
cw[i].u++; cw[i].v++;
if(cw[i].u > cw[i].v) swap(cw[i].u, cw[i].v);
}
int L = 1, R = n, mid, ans = 0;
while(L <= R) {
mid = (L + R) >> 1;
if(ok(mid)) ans = mid, L = mid + 1;
else R = mid - 1;
}
printf("%d\n", ans-1);
return 0;
}
//二分+匈牙利
#include<bits/stdc++.h>
#define clr(a, b) memset(a,b,sizeof((a)))
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
typedef long long LL;
const int MXN = 2e4 + 7;
const LL mod = 998244353;
int n, m;
struct lp {
int u, v;
}cw[MXN];
std::vector<int> son[MXN];
int vis[MXN], be[MXN], is[MXN];
bool dfs(int u){
for(auto x : son[u]){
if(vis[x]) continue;
vis[x] = 1;
if(is[x] == -1 || dfs(is[x])){
is[x] = u;
be[u] = x;
return true;
}
}
return false;
}
bool ok(int mid) {
for(int i = 1; i <= n; ++i) son[i].clear();
for(int i = 0; i < m; ++i) {
if(cw[i].v >= mid && cw[i].u < mid) {
son[cw[i].u].push_back(cw[i].v);
}
}
for(int i = 1; i <= n; ++i) is[i] = be[i] = -1;
int cnt = 0;
for(int i = 1; i <= n; ++i){
if(be[i] != -1) continue;
for(int j = 1; j <= n; ++j) vis[j] = 0;
if(dfs(i)) cnt++;
}
return cnt == mid-1;
}
int main() {
scanf("%d%d", &n, &m);
for(int i = 0; i < m; ++i) {
scanf("%d%d", &cw[i].u, &cw[i].v);
cw[i].u++; cw[i].v++;
if(cw[i].u > cw[i].v) swap(cw[i].u, cw[i].v);
}
int L = 1, R = n, mid, ans = 0;
while(L <= R) {
mid = (L + R) >> 1;
if(ok(mid)) ans = mid, L = mid + 1;
else R = mid - 1;
}
printf("%d\n", ans-1);
return 0;
}
//
8E div2 Souls-like Game (矩阵乘法 优化)
//vector被卡常数了,死活过不去卧槽
//div2就是一个矩阵乘法,div1要用线段树优化一下
//不过说实话,这个n*m*9的复杂度能过这一题,我也是醉了
#include<bits/stdc++.h>
#define clr(a, b) memset(a,b,sizeof((a)))
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
typedef long long LL;
const int MXN = 1e4 + 7;
const LL mod = 998244353;
int n, m;
LL sum[2][3];
int ar[MXN][3][3], tmp[3][3];
int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i < n; ++i) {
for(int j = 0; j < 3; ++j) {
for(int k = 0; k < 3; ++k) {
scanf("%d", &ar[i][j][k]);
}
}
}
int opt, l, r;
while(m --) {
scanf("%d%d%d", &opt, &l, &r);
if(opt == 1) {
for(int i = 0; i < 3; ++i) for(int j = 0; j < 3; ++j) scanf("%d", &tmp[i][j]);
for(int i = l; i <= r; ++i) for(int j = 0; j < 3; ++j) for(int k = 0; k < 3; ++k) {
ar[i][j][k] = tmp[j][k];
}
}else {
opt = 1;
sum[0][0] = sum[0][1] = sum[0][2] = 1;
for(int i = l; i < r; ++i) {
for(int j = 0; j < 3; ++j) sum[opt][j] = 0;
for(int k = 0; k < 3; ++k) {
for(int j = 0; j < 3; ++j) {
sum[opt][j] = (sum[opt][j]+sum[opt^1][k]*ar[i][k][j])%mod;
}
}
opt ^= 1;
}
printf("%lld\n", (sum[opt^1][0]+sum[opt^1][1]+sum[opt^1][2])%mod);
}
}
return 0;
}
8E div1 Souls-like Game (线段树+矩阵乘法)
//哇,这题ac完感觉好爽啊
//第一次写这种结构体线段树还重载操作符的,舒服
//没有人写博客,只能看着官方题解意会解法
#include<bits/stdc++.h>
#define clr(a, b) memset(a,b,sizeof((a)))
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
typedef long long LL;
const int MXN = 2e5 + 7;
const LL mod = 998244353;
int n, m, Q;
int ar[MXN][3][3], two[33];
int lazy[MXN<<2][3][3], flag[MXN<<2];
map<int, int> mp;
struct edge {
int opt, l, r;
int ar[3][3];
}node[MXN];
struct lp {
int sum[3][3];
friend lp operator *(const lp&a, const lp&b) {
lp c;
clr(c.sum, 0);
for(int k = 0; k < 3; ++k) for(int i = 0; i < 3; ++i) for(int j = 0; j < 3; ++j) {
c.sum[i][j] = (c.sum[i][j]+(LL)a.sum[i][k]*b.sum[k][j])%mod;
}
return c;
}
}cw[MXN<<2], tp[MXN][33];
void push_up(int rt) {
cw[rt] = cw[lson] * cw[rson];
}
void build(int l,int r,int rt) {
flag[rt] = -1;
if(l == r) {
for(int i = 0; i < 3; ++i) for(int j = 0; j < 3; ++j) cw[rt].sum[i][j] = ar[l][i][j];
return ;
}
int mid = (l + r) >> 1;
build(l, mid, lson); build(mid+1,r,rson);
push_up(rt);
}
void push_down(int l,int mid,int r,int rt) {
if(flag[rt] == -1) return;
flag[lson] = flag[rson] = flag[rt];
for(int i = 0; i < 3; ++i) for(int j = 0; j < 3; ++j) lazy[lson][i][j] = lazy[rt][i][j], lazy[rson][i][j] = lazy[rt][i][j];
cw[lson] = tp[flag[rt]][mp[mid-l+1]-1];
cw[rson] = tp[flag[rt]][mp[r-mid]-1];
assert(mp[mid-l+1]); assert(mp[r-mid]);
flag[rt] = -1;
}
void update(int L,int R,int id,int l,int r,int rt) {
if(L <= l && r <= R) {
flag[rt] = id;
for(int i = 0; i < 3; ++i) for(int j = 0; j < 3; ++j) lazy[rt][i][j] = node[id].ar[i][j];
assert(mp[r-l+1]);
cw[rt] = tp[id][mp[r-l+1]-1];
return ;
}
int mid = (l + r) >> 1;
push_down(l, mid, r, rt);
if(L > mid) update(L, R, id, mid+1, r, rson);
else if(R <= mid) update(L, R, id, l, mid, lson);
else {
update(L,mid,id,l,mid,lson); update(mid+1,R,id,mid+1,r,rson);
}
push_up(rt);
}
lp query(int L,int R,int l,int r,int rt) {
if(L <= l && r <= R) {
return cw[rt];
}
int mid = (l + r) >> 1;
push_down(l, mid, r, rt);
if(L > mid) return query(L, R, mid+1, r, rson);
else if(R <= mid) return query(L, R, l, mid, lson);
else {
return query(L,mid,l,mid,lson)*query(mid+1,R,mid+1,r,rson);
}
}
int main() {
two[0] = 1, mp[1] = 1;
for(int i = 1; i <= 17; ++i) two[i] = two[i-1] << 1, mp[1<<i] = i + 1;
//printf("%d %d\n", two[17], mp[1<<17]-1);
scanf("%d%d", &n, &Q);
for(int i = 1; i < n; ++i) {
for(int j = 0; j < 3; ++j) for(int k = 0; k < 3; ++k) scanf("%d", &ar[i][j][k]);
}
m = 2;
while(m < n) m <<= 1;
build(1, m, 1);
int opt, l, r;
for(int i = 1; i <= Q; ++i) {
scanf("%d%d%d", &node[i].opt, &node[i].l, &node[i].r);
if(node[i].opt == 1) {
for(int k = 0; k < 3; ++k) for(int j = 0; j < 3; ++j) {
scanf("%d", &node[i].ar[k][j]);
tp[i][0].sum[k][j] = node[i].ar[k][j];
}
for(int k = 1; k <= 17; ++k) {
tp[i][k] = tp[i][k-1] * tp[i][k-1];
}
/*printf("***\n");
for(int h = 0; h < 3; ++ h) {
for(int k = 0; k < 3; ++k) {
for(int j = 0; j < 3; ++j) {
printf("%d ", tp[i][h].sum[k][j]);
}
printf("\n");
}
}*/
update(node[i].l, node[i].r, i, 1, m, 1);
}else {
LL ans = 0;
lp a = query(node[i].l, node[i].r-1, 1, m, 1);
for(int i = 0; i < 3; ++i) for(int j = 0; j < 3; ++j) ans = (ans + a.sum[i][j]) % mod;
printf("%lld\n", ans);
}
}
return 0;
}
8I div1 岸边露伴的人生经验 (FWT)
//题解 https://blog.csdn.net/qq_39599067/article/details/86747863
#include<bits/stdc++.h>
#define clr(a, b) memset(a,b,sizeof((a)))
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
typedef long long LL;
const int MXN = 3e5 + 7;
const int MOD = 998244353;
int n, m, Q;
int LN;
LL ar[1<<21], br[MXN], inv2;
LL ksm(LL a, int b) {
LL res = 1;
for(; b; b>>=1, a=a*a%MOD) {
if(b&1) res = res * a % MOD;
}
return res;
}
void FWT_xor(LL *a,int LN,int opt) {
for(int i=1;i<LN;i<<=1)
for(int p=i<<1,j=0;j<LN;j+=p)
for(int k=0;k<i;++k) {
LL X=a[j+k],Y=a[i+j+k];
a[j+k]=(X+Y)%MOD;a[i+j+k]=(X+MOD-Y)%MOD;
if(opt==-1)a[j+k]=a[j+k]*inv2%MOD,a[i+j+k]=a[i+j+k]*inv2%MOD;
}
}
int main() {
inv2 = ksm(2, MOD - 2);
scanf("%d", &n);
for(int i = 0, tmp; i < n; ++i) {
tmp = 0;
for(int j = 0, x; j < 10; ++j) {
scanf("%d", &x);
if(x == 0) tmp <<= 2;
else if(x == 1) tmp <<= 2, tmp |= 1;
else tmp <<= 1, tmp |= 1, tmp <<= 1;
}
++ ar[tmp];
}
LN = (1<<20);
FWT_xor(ar, LN, 1);
for (int i = 0; i < LN; ++i) ar[i] = ar[i] * ar[i] % MOD;
FWT_xor(ar, LN, -1);
//ar[x] 表示有多少对ai和aj异或结果为x
LL ans = 0;
for(int i = 0, tmp, cnt; i < LN; ++i) {
tmp = i; cnt = 0;
for(int j = 0, x; j < 10; ++j) {
x = tmp & 3;
if(x == 3) x = 1;
if(x == 2) x = 4;
cnt += x;
tmp >>= 2;
}
br[cnt] = (br[cnt] + ar[i]) % MOD;
}
for(int i = 0; i <= 40; ++i) {
ans = (ans + br[i]*br[i]%MOD)%MOD;
}
printf("%lld\n", ans);
return 0;
}