暑假集训8
A. T1 出了个大阴间题
40分的dfs:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 25; const ll mod = 1e9 + 7; int n, b[maxn], c[maxn]; ll ans, Maxa, k; bool v[maxn]; inline int read() { int 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; } void check() { ll nowa = c[b[1]], nowb = 0, nowans = 0; for(int i=2; i<=n; i++) { if(nowa != c[b[i]]) { nowa = max(nowa, (ll)c[b[i]]); } else nowa++; nowans = (nowans+k*nowa%mod+nowb)%mod; nowb = (nowb<<1)+1; } //printf("nowa = %lld\n", nowa); //printf("nowans = %lld\n\n", nowans); if(nowa > Maxa) { ans = nowans; Maxa = nowa; } else if(nowa == Maxa) { ans = (ans + nowans) % mod; } return; } void dfs(int a, int n) { if(a > n) { check(); return; } for(int i=1; i<=n; i++) { if(v[i]) continue; v[i] = 1; b[a] = i; dfs(a+1, n); v[i] = 0; } } int main() { freopen("repair.in", "r", stdin); freopen("repair.out", "w", stdout); n = read(); k = read(); for(int i=1; i<=n; i++) { c[i] = read(); } dfs(1, n); printf("%lld %lld\n", Maxa, ans); return 0; }
鹤个题解:(不知道用哪个he就选个好看的)
f[i]表示当前状态,f[i].first是maxa,f[i].second是maxa确定的所有方案的代价总和,g[i]记录从g[1]到g[i-1]累加的maxa特定的所有方案数,num用来记录b的个数,可以从二进制下任意去掉一个1的状态转移,b预处理b的值[我在写dfs时就发现了b的影响只和个数有关的事,但是由于没有想到状压,也没有用到]。
map似乎是个好东西可以把maxval和答案存到一起。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; const int maxn = 6e5 + 21; const ll mod = 1e9 + 7; int m, n, U, maxval, val[25], b[25]; ll num[1<<18]; map<int, ll> f[1<<18], g[1<<18]; inline int read() { int 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 main() { freopen("repair.in", "r", stdin); freopen("repair.out", "w", stdout); n = read(); m =read(); U = (1<<n)-1; for(int i=1; i<=n; i++) val[i] = read(); for(int i=2; i<=n; i++) b[i] = b[i-1]<<1|1; for(int i=1; i<=n; i++) { f[1<<(i-1)][val[i]] = 0; g[1<<(i-1)][val[i]]++; } for(int i=1; i<U; i++) { num[i] = num[i&(i-1)]+1; for(int j=1,k; j<=n; j++) { if((i>>(j-1))&1) continue; k = i|(1<<(j-1)); for(auto c : f[i]) { ll to = (c.first==val[j]?val[j]+1:max(c.first, val[j])); f[k][to] = (f[k][to]+f[i][c.first]+(to*m%mod+b[num[i]])%mod*g[i][c.first]%mod)%mod; g[k][to] = (g[k][to]+g[i][c.first])%mod; } } } for(auto i : f[U]) maxval = max(maxval, i.first); printf("%d %lld", maxval, f[U][maxval]%mod); return 0; }
B. T2 最简单辣快来做
我盯着这个编号为奇数的测试点保证a,b与M互质看了好半天想不出来如果不互质会怎样,到最后也没看明白,好像暴力和正解都和它无关……
正解有一些神奇的预处理:
1.光速幂,其实就是一种分块,ra存整的,bsa存余数,然后就可以搭配了。
2.不需要每次查询都算一遍答案,用0123记录一下以每一个点为通信中心时的各个方向的区域的总贡献,查询时只要找到查询点和它旁边离它最近(周围就行)的点,直接用统计好的贡献加上有了查询点之后偏移造成的新贡献就好了。统计贡献时的循环其实就是前缀和的套路。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; const int block = 50000, maxn = 2004; int n, q; ll mod, a, b; int x[maxn], y[maxn], fx[maxn], fy[maxn], h[maxn]; ll ra[block+100], rb[block+100], bsa[block+100], bsb[block+100]; ll sum[maxn][maxn][4]; inline ll read() { 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; } inline ll powa(ll zhi) {return ra[zhi/block]*bsa[zhi%block]%mod; } inline ll powb(ll zhi) {return rb[zhi/block]*bsb[zhi%block]%mod; } inline void Prework() { bsa[0] = bsb[0] = ra[0] = rb[0] = 1; for(int i=1; i<=block; i++) { bsa[i] = bsa[i-1]*a%mod; bsb[i] = bsb[i-1]*b%mod; } for(int i=1; i<=block; i++) { ra[i] = ra[i-1]*bsa[block]%mod; rb[i] = rb[i-1]*bsb[block]%mod; } sort(fx+1, fx+1+n); sort(fy+1, fy+1+n); for(int i=1; i<=n; i++) { x[i] = lower_bound(fx+1, fx+1+n, x[i])-fx; y[i] = lower_bound(fy+1, fy+1+n, y[i])-fy; sum[x[i]][y[i]][0] = sum[x[i]][y[i]][1] = sum[x[i]][y[i]][2] = sum[x[i]][y[i]][3] = h[i]; } for(int i=1; i<=n; i++) { for(int j=1; j<=n; j++) { sum[i][j][0] = (sum[i][j][0]+sum[i][j-1][0]*powb(fy[j]-fy[j-1])%mod)%mod; } for(int j=1; j<=n; j++) { sum[i][j][0] = (sum[i][j][0]+sum[i-1][j][0]*powa(fx[i]-fx[i-1])%mod)%mod; } for(int j=n; j>=1; j--) { sum[i][j][1] = (sum[i][j][1]+sum[i][j+1][1]*powb(fy[j+1]-fy[j])%mod)%mod; } for(int j=n; j>=1; j--) { sum[i][j][1] = (sum[i][j][1]+sum[i-1][j][1]*powa(fx[i]-fx[i-1])%mod)%mod; } } for(int i=n; i>=1; i--) { for(int j=1; j<=n; j++) { sum[i][j][2] = (sum[i][j][2]+sum[i][j-1][2]*powb(fy[j]-fy[j-1])%mod)%mod; } for(int j=1; j<=n; j++) { sum[i][j][2] = (sum[i][j][2]+sum[i+1][j][2]*powa(fx[i+1]-fx[i])%mod)%mod; } for(int j=n; j>=1; j--) { sum[i][j][3] = (sum[i][j][3]+sum[i][j+1][3]*powb(fy[j+1]-fy[j])%mod)%mod; } for(int j=n; j>=1; j--) { sum[i][j][3] = (sum[i][j][3]+sum[i+1][j][3]*powa(fx[i+1]-fx[i])%mod)%mod; } } } inline ll Work(int px, int py) { int dx = upper_bound(fx+1, fx+1+n, px)-fx; int dy = upper_bound(fy+1, fy+1+n, py)-fy; ll res = 0; if(dx-1 && dy-1) { res = (res+sum[dx-1][dy-1][0]*powa(px-fx[dx-1])%mod*powb(py-fy[dy-1])%mod)%mod; } if(dx-1 && dy<=n) { res = (res+sum[dx-1][dy][1]*powa(px-fx[dx-1])%mod*powb(fy[dy]-py)%mod)%mod; } if(dx<=n && dy-1) { res = (res+sum[dx][dy-1][2]*powa(fx[dx]-px)%mod*powb(py-fy[dy-1])%mod)%mod; } if(dx<=n && dy<=n) { res = (res+sum[dx][dy][3]*powa(fx[dx]-px)%mod*powb(fy[dy]-py)%mod)%mod; } return res; } int main() { freopen("satellite.in", "r", stdin); freopen("satellite.out", "w", stdout); n = read(); q = read(); read(); read(); mod = read(); a = read(); b = read(); for(int i=1; i<=n; i++) { h[i] = read(); x[i] = fx[i] = read(); y[i] = fy[i] = read(); } Prework(); for(int i=1; i<=q; i++) { int per = read(), qer = read(); printf("%lld\n", Work(per, qer)); } return 0; }
C. T3 是我的你不要抢
第一印象:这不就是AC自动机专题里的 玄武密码 吗?于是经过string优化空间和离线问题之类的一顿改编然后发现样例都过不了,才发现没看到只能用后缀……
一顿魔改,小样例终于过了但是大样例就是不对,到最后交了一个错的+特判,然后特判有分。
对着caorong的改了一下午KMP,T了个71:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1e6 + 2; const int N = 6e5 + 2; const ll mod = 1e9 + 7; const int inf = (1<<29); int n, Q, nxt[N], f[N], len1, len2, ans[maxn]; vector<string> t; string s; inline int read() { int 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; } struct node { int x, y, id; bool operator < (const node &T) const { if(y == T.y) return x < T.x; return y < T.y; } }q[maxn]; int main() { freopen("string.in", "r", stdin); freopen("string.out", "w", stdout); n = read(); Q = read(); for(register int i=1; i<=n; i++) { cin >> s; s = '0'+s; t.push_back(s); } for(register int i=1; i<=Q; i++) { q[i].x = read()-1; q[i].y = read()-1; q[i].id = i; } sort(q+1, q+1+Q); for(register int i=1; i<=Q; ) { int l = i, r = i; while(q[r+1].y == q[l].y && r+1<=Q) r++; for(register int j=1; j<len1; j++) nxt[j] = 0; int y = q[i].y; len1 = t[y].size(); //cout << t[y] << endl; for(register int o=2,j=0; o<len1; o++) { while(j > 0 && t[y][o] != t[y][j+1]) j = nxt[j]; //if(t[y][o] == t[y][j+1]) j++; //nxt[o] = j; if(t[y][o] == t[y][j+1]) nxt[o] = ++j; //printf("nxt[%d] = %d\n", o, nxt[o]); } //for(int j=1; j<=len2; j++) f[j] = 0; for(register int op=l; op<=r; op++) { if(op > l && q[op].x == q[op-1].x) { ans[q[op].id] = ans[q[op-1].id]; continue; } for(register int j=1; j<len2; j++) f[j] = 0; int x = q[op].x; len2 = t[x].size(); //cout << t[x] << endl; int st = max(1, len2-len1+1); for(register int o=1,j=0; o<len2; o++) { while(j > 0 && t[x][o] != t[y][j+1]) j = nxt[j]; //if(t[x][o] == t[y][j+1]) j++; //f[o] = j; if(t[x][o] == t[y][j+1]) f[o] = ++j; //printf("f[%d] = %d\n", o, f[o]); } ans[q[op].id] = f[len2-1]; } for(register int i=1; i<=len2; i++) f[i] = 0; i = r+1; } for(register int i=1; i<=Q; i++) { printf("%d\n", ans[i]); } return 0; }
又抄了个hash的A了,然后被同学的鬼畜数据卡成了99:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; const int maxn = 6e5 + 21; const ull B = 131; int n, Q, maxlen, ans, len[maxn]; char s[maxn]; ull po[maxn]; vector<ull> c[maxn], pre[maxn]; unordered_map<int, ull> mp1[maxn]; inline int read() { int 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; } inline ull getsh(int x, int l, int r) { return pre[x][r]-pre[x][l-1]*po[r-l+1]; } int main() { freopen("string.in", "r", stdin); freopen("string.out", "w", stdout); n = read(); Q = read(); for(int i=1; i<=n; i++) { scanf("%s", s+1); c[i].push_back(0); pre[i].push_back(0); len[i] = strlen(s+1); maxlen = max(maxlen, len[i]); for(int j=1; j<=len[i]; j++) { c[i].push_back(s[j]-'a'+1); pre[i].push_back(pre[i][j-1]*B+c[i][j]); } } po[0] = 1; for(int i=1; i<=maxlen; i++) po[i] = po[i-1]*B; while(Q--) { int y = read(), x = read(); maxlen = min(len[x], len[y]); if(mp1[x].find(y) != mp1[x].end()) { printf("%lld\n", mp1[x][y]); continue; } for(int i=maxlen; i>=0; i--) { if(getsh(x, 1, i) == getsh(y, len[y]-i+1, len[y])) { ans = i; break; } } mp1[x][y] = ans; printf("%d\n", ans); } return 0; }
D. T4 显然也是我整的
当我发现s<=n/2的答案就是把s求个gcd之后,不知道大一点的s怎么办了,本着骗分的思路交了一个gcd,结果(⊙o⊙)…一分都没有,输出1或暴力并查集建图好像都有分的……
以下是正解的代码但不是我写的,CV一下不想改了**
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//CV题解很有瘾 #include <bits/stdc++.h> #define int long long #define ull unsigned long long #define f() cout<<"Failed"<<endl using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f; } const int N=2e5+10; int n,m,T,top,sta[N],s[N]; set<int> se; void work(int &ans,int &n) { int num=(*se.begin()),temp=2*num-n; for(auto it=se.begin();it!=se.end();it++) sta[++top]=(*it); ans+=temp; n-=temp; se.clear(); for(int i=1;i<=top;i++) se.insert(sta[i]-temp); } int solve(int n) { int ans=top=0,gcd=0; if((*se.begin())>n/2) work(ans,n); for(auto it=se.begin();it!=se.end();it++) if((*it)<=n/2) gcd=__gcd(gcd,(*it)); else break; se.erase(se.begin(),se.upper_bound(n/2)); for(auto it=se.begin();it!=se.end();it++) if((*it)+gcd<=n) gcd=__gcd(gcd,(*it)); else break; se.erase(se.begin(),se.upper_bound(n-gcd)); if(!se.size()) return ans+gcd; int temp=gcd+n%gcd; top=0; for(auto it=se.begin();it!=se.end();it++) sta[++top]=(*it); se.clear(); for(int i=1;i<=top;i++) se.insert(temp+sta[i]-n); se.insert(gcd); return ans+solve(temp); } signed main() { freopen("graph.in","r",stdin); freopen("graph.out","w",stdout); T=read(); while(T--) { n=read(); m=read(); se.clear(); for(int i=1;i<=m;i++) s[i]=read(); for(int i=1;i<=m;i++) se.insert(s[i]); printf("%lld\n",solve(n)); } return 0; }