XVII Open Cup named after E.V. Pankratiev. XXI Ural Championship
A. Apple
按题意模拟即可。
#include<stdio.h> #include<iostream> #include<string.h> #include<string> #include<ctype.h> #include<math.h> #include<set> #include<map> #include<vector> #include<queue> #include<bitset> #include<algorithm> #include<time.h> using namespace std; void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); } #define MS(x, y) memset(x, y, sizeof(x)) #define ls o<<1 #define rs o<<1|1 typedef long long LL; typedef unsigned long long UL; typedef unsigned int UI; template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; } template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; } const int N = 105, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f; template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; } int casenum, casei; int n, m; vector<int>a[N]; int ind1 = 0, ind1num = 0; int ind2num = 0; int ind3 = 0, ind3num = 0; bool vis[N]; int ind[N]; int cnt; bool dfs1(int x, int fa) { ++cnt; vis[x] = 1; for(auto y : a[x])if(y != fa) { if(!vis[y]) { if(!dfs1(y, x))return 0; } else if(y != ind3)return 0; } return 1; } void dfs3(int x, int fa) { ++cnt; vis[x] = 1; for(auto y : a[x])if(y != fa) { if(!vis[y]) { dfs3(y, x); } } } bool solve() { if(ind1num != 1)return 0; if(ind2num != n - 2)return 0; if(ind3num != 1)return 0; cnt = 0; vis[ind3] = true; if(!dfs1(ind1, 0))return 0; dfs3(ind3, 0); if(cnt != n)return 0; return 1; } int main() { freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); while(~scanf("%d%d", &n, &m)) { for(int i = 1; i <= n; ++i) { a[i].clear(); ind[i] = 0; vis[i] = 0; } for(int i = 1; i <= m; ++i) { int x, y; scanf("%d%d", &x, &y); a[x].push_back(y); a[y].push_back(x); ++ind[x]; ++ind[y]; } ind1 = 0, ind1num = 0; ind2num = 0; ind3 = 0, ind3num = 0; for(int i = 1; i <= n; ++i) { if(ind[i] == 1) { ++ind1num; ind1 = i; } else if(ind[i] == 2) { ++ind2num; } else if(ind[i] == 3) { ++ind3num; ind3 = i; } } puts(solve() ? "Yes" : "No"); } return 0; } /* 【trick&&吐槽】 【题意】 【分析】 【时间复杂度&&优化】 9 9 1 2 2 3 3 5 5 6 6 4 4 7 1 7 7 9 8 9 5 5 1 2 2 3 1 3 1 4 1 5 4 4 1 2 2 3 1 3 1 4 5 4 1 2 2 3 1 3 1 4 */
B. Bar charts
关于序列的前缀和建立差分约束系统,SPFA判断是否存在负环。
#include<cstdio> #include<cstdlib> using namespace std; const int N=12222,M=1000000,E=10000000,inf=~0U>>1; int n,i,g[N],v[M],w[M],nxt[M],ed,d[N]; int x,h,t,q[E]; int vis[N],in[N]; inline void add(int x,int y,int z){v[++ed]=y;w[ed]=z;nxt[ed]=g[x];g[x]=ed;} inline void make(int x,int y,int z){ //x-y=z add(y,x,z); add(x,y,-z); } void gao(){ int k,b,s; scanf("%d%d%d",&k,&b,&s); make(b-1,0,0); for(int i=b+k*s;i<=n;i++)make(i,i-1,0); for(int i=1;i<=k;i++){ int l=b+(i-1)*s,r=b+i*s; int o; scanf("%d",&o); //s[r-1]-s[l-1] make(r-1,l-1,o); } } void NO(){ puts("No"); exit(0); } inline void ext(int x,int y){ if(y<0)NO(); if(y>=d[x])return; d[x]=y; if(!in[x]){ in[x]=1; vis[x]++; if(vis[x]>=n)NO(); q[++t]=x; if(t>=E-10)NO(); } } int main(){ freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); n=11111; for(i=0;i<n;i++)add(i+1,i,0); gao(); gao(); for(i=0;i<=n;i++){ d[i]=inf; } h=1,t=0; ext(0,0); while(h<=t){ x=q[h++]; for(i=g[x];i;i=nxt[i])ext(v[i],d[x]+w[i]); in[x]=0; } puts("Yes"); }
C. Construction sets
二分答案,二进制拆分背包+bitset检验。
#include<stdio.h> #include<iostream> #include<string.h> #include<string> #include<ctype.h> #include<math.h> #include<set> #include<map> #include<vector> #include<queue> #include<bitset> #include<algorithm> #include<time.h> using namespace std; void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); } #define MS(x, y) memset(x, y, sizeof(x)) #define ls o<<1 #define rs o<<1|1 typedef long long LL; typedef unsigned long long UL; typedef unsigned int UI; template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; } template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; } const int N = 55, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f; template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; } int casenum, casei; int n, mn, mx; int m[N], c[N]; bitset<10005>f; bool check(int K) { f.reset(); f[0] = 1; for(int i = 1; i <= n; ++i) { int tot = c[i] / K; int g = 1; LL v = m[i]; while(tot) { if(v > mx)break; f |= f << v; tot -= g; g = min(g * 2, tot); v = (LL)m[i] * g; } } for(int j = mn; j <= mx; ++j) { if(f[j])return 1; } return 0; } int main() { freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); while(~scanf("%d%d%d", &n, &mn, &mx)) { for(int i = 1; i <= n; ++i) { scanf("%d%d", &m[i], &c[i]); } int l = 0; int r = 1e6; while(l < r) { int mid = (l + r + 1) >> 1; if(check(mid)) { l = mid; } else { r = mid - 1; } } printf("%d\n", l); } return 0; } /* 【trick&&吐槽】 【题意】 【分析】 【时间复杂度&&优化】 3 12 13 3 8 4 6 7 9 */
D. Dinner party
$f[i][j]$表示面积和为$i$的矩形,周长和为$j$是否有可能,bitset加速。
#include<cstdio> #include<bitset> using namespace std; const int N=1010,M=2010; int T,n,m,i,j,x,y,cnt; bitset<M>f[N]; void solve(){ scanf("%d%d",&n,&m); if(m%2){ puts("No"); return; } m/=2; if(f[n][m]==0){ puts("No"); return; } puts("Yes"); int cnt=0; static int q[100000][2]; while(n){ int X=0,Y=0; for(x=1;x<=n;x++){ for(y=1;y*x<=n;y++)if(x+y<=m)if(f[n-x*y][m-x-y]){ X=x,Y=y; break; } if(X)break; } q[++cnt][0]=X; q[cnt][1]=Y; n-=X*Y; m-=X+Y; } printf("%d\n",cnt); for(int i=1;i<=cnt;i++)printf("%d %d\n",q[i][0],q[i][1]); } int main(){ freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); //scanf("%d%d",&n,&m); n=1000; m=2000; f[0][0]=1; for(i=0;i<=n;i++) for(x=1;x+i<=n;x++) for(y=1;x*y+i<=n;y++) f[i+x*y]|=f[i]<<(x+y); scanf("%d",&T); while(T--)solve(); }
E. Expression on dice
若要构造$=$,则在两侧构造$0$即可,否则随意构造。
// // main.cpp // opencup 10378 E // // Created by luras on 2017/9/14. // Copyright © 2017年 luras. All rights reserved. // #define ms(x, y) memset(x, y, sizeof(x)) #define mc(x, y) memcpy(x, y, sizeof(x)) #define lson o << 1, l, mid #define rson o << 1 | 1, mid + 1, r #define ls o << 1 #define rs o << 1 | 1 #include<stdio.h> #include<string.h> #include<math.h> #include<queue> #include<map> #include<stack> #include<time.h> #include<vector> #include<list> #include<set> #include<iostream> #include<stdlib.h> #include<string> #include<algorithm> #pragma comment(linker,"/STACK:102400000,102400000") template <class T> inline void gmax(T &a, T b){if(b > a) a = b;} template <class T> inline void gmin(T &a, T b){if(b < a) a = b;} using namespace std; const int N = 1e6 + 10, M = 2e6 + 10, Z = 1e9 + 7, maxint = 2147483647, ms1 = 16843009, ms31 = 522133279, ms63 = 1061109567, ms127 = 2139062143; const double PI = acos(-1.0), eps = 1e-8; typedef long long LL; void fre() { freopen("/Users/luras/Desktop/in.txt", "r", stdin); freopen("/Users/luras/Desktop/out.txt", "w", stdout); } const int INF = 1e9; int casenum, casei; int priv[N]; double calc(double a, double b, char op) { if(op == '+') return a + b; if(op == '-') return a - b; if(op == '*') return a * b; if(op == '/') return a / b; return 0; } double calculate(string str) { stack<double> num; stack<char> oper; priv['+'] = priv['-'] = 3; priv['*'] = priv['/'] = 2; priv['('] = 10; double x, y, t = 0; int i; char last = 0; for(i = 0; i < str.length(); i ++){ if(isdigit(str[i])){ num.push(atof(str.c_str() + i)); for(; i + 1 < str.length() && isdigit(str[i + 1]); i ++); if(i + 1 < str.length() && str[i + 1] == '.') for(i ++; i + 1 < str.length() && isdigit(str[i + 1]); i ++); } else if(str[i] == '('){ oper.push(str[i]); } else if(str[i] == ')'){ while(oper.top() != '('){ y = num.top(); num.pop(); x = num.top(); num.pop(); char op = oper.top(); oper.pop(); num.push(calc(x, y, op)); } oper.pop(); } else if(str[i] == '-' && (last == 0 || last == '(')){ num.push(0.0); oper.push('-'); } else if(priv[str[i]] > 0){ while(oper.size() > 0 && priv[str[i]] >= priv[oper.top()]){ y = num.top(); num.pop(); x = num.top(); num.pop(); char op = oper.top(); oper.pop(); num.push(calc(x, y, op)); } oper.push(str[i]); }else continue; last = str[i]; } while(oper.size() > 0){ y = num.top(); num.pop(); x = num.top(); num.pop(); char op = oper.top(); oper.pop(); num.push(calc(x, y, op)); } return num.top(); } map<int, bool> mop; vector<int> num; vector<char> sym; int lft, rgt, zero, divi, typ; const string sta[6][6] ={ {"=", "<", ">", "!=", "<=", ">="}, {"4", "+", "-", "(", "(", ")"}, {"0", "/", "/", "/", "8", "+"}, {"2", "3", "4", "5", "-", ")"}, {"+", "-", "*", "/", "1", "9"}, {"6", "7", "+", "-", "(", ")"} }; void ask(int o) { char ch; if(o == 2){ puts("2"); fflush(stdout); scanf(" %c", &ch); //ch = sta[1][rand() % 6][0]; //cout << "A: " << ch; if(ch == '(') lft ++; else if(ch == ')') rgt ++; else if(ch == '4') { num.push_back(ch); if(mop[ch] == 0){ mop[ch] = 1; typ ++; } } else sym.push_back(ch); } else if(o == 3){ puts("3"); fflush(stdout); scanf(" %c", &ch); //ch = sta[2][rand() % 6][0]; //cout << "A: " << ch; if(ch == '0') zero ++; else if(ch == '8') { num.push_back(ch); if(mop[ch] == 0){ mop[ch] = 1; typ ++; } } else if(ch == '/') divi ++; else sym.push_back(ch); } else if(o == 4){ puts("4"); fflush(stdout); //ch = sta[3][rand() % 6][0]; //cout << "A: " << ch; scanf(" %c", &ch); if(ch == '-') sym.push_back(ch); else if(ch == ')') rgt ++; else { num.push_back(ch); if(mop[ch] == 0){ mop[ch] = 1; typ ++; } } } } string ans; string s; string ss; int sgn(double x) { if(fabs(x) < eps) return 0; return x > 0 ? 1 : -1; } bool choose() { s = ""; int DIV = divi, ZERO = zero; int n = num.size(), m = sym.size() + DIV; int bas = (n + ZERO) / (m + 1); int mo = (n + ZERO) - (m + 1) * bas; int t = 0, j = -1, k = -1; for(int i = 0; i < m + 1; i ++){ if(mo){ if(j + 1 >= n) return 0; // 必须得放前导0了 s += num[++ j]; ++ t; while(t <= bas && ZERO){ s += '0'; t ++; ZERO --; } while(t <= bas){ s += num[++ j]; t ++; } mo --; t = 0; } else{ if(j + 1 >= n) return 0; s += num[++ j]; ++ t; while(t < bas && ZERO){ s += '0'; t ++; ZERO --; } while(t < bas){ s += num[++ j]; t ++; } t = 0; } if(DIV){ s += '/'; DIV --; } else{ if(k + 1 < sym.size())s += sym[++ k]; } } return 1; } bool check(int o) { if(o == 0){ zero -= 2; lft --; rgt --; divi --; if(!choose()) {zero += 2; lft ++; rgt ++; divi ++; return 0;} if(calculate(s) != 0){ ans = ""; for(int i = 0; i < lft; i ++) ans += '('; ans += '0'; for(int i = 0; i < rgt; i ++) ans += ')'; ans += "=0/(" + s + ')'; } else {zero += 2; lft ++; rgt ++; divi ++; return 0;} } else{ zero --; if(!choose()) {zero ++;return 0;} double tmp = calculate(s); if(sgn(tmp) != 0){ if(ss[0] == '<' && sgn(tmp) > 0 || ss[0] == '>' && sgn(tmp) < 0){ ans = ""; for(int i = 0; i < lft; i ++) ans += '('; ans += '0'; for(int i = 0; i < lft; i ++) ans += ')'; ans += ss + s; } else{ ans = ""; for(int i = 0; i < lft; i ++) ans += '('; ans += s; for(int i = 0; i < lft; i ++) ans += ')'; ans += ss + '0'; } } else if(ss == "!="){ ans = ""; for(int i = 0; i < lft; i ++) ans += '('; ans += '0'; for(int i = 0; i < lft; i ++) ans += ')'; ans += ss + s; } else {zero ++; return 0;} } return 1; } int main() { srand(time(NULL)); //fre(); puts("1"); fflush(stdout); cin >> ss; //ss = sta[0][rand() % 6]; //cout << ss << endl; lft = rgt = zero = divi = typ = 0; int tim = 0; while(1){ if(++ tim == 1000){ int go = 1; } if(zero < (ss[0] == '=' ? 2 : 1) || divi == 0){ ask(3); } else if(lft < rgt || lft == 0){ ask(2); } else if(num.size() - 2 < sym.size() || rgt < lft){ ask(4); } else { if(check(ss[0] == '=' ? 0 : 1)) break; ask(4); } } printf("0 "); cout << ans << endl; fflush(stdout); return 0; } /* 题意: 类型: 分析: 优化: trick: 数据: Sample Input Sample Output >= + / / + 8 0 ) ( ) ( - - 5 5 5 - 4 4 4 - 5 3 */
F. Flight trip
留坑。
G. Glasses with solutions
找出的子集需要满足$b\sum m-a\sum t=0$,折半搜索即可。
#include<cstdio> #include<map> using namespace std; typedef long long ll; const int N=40; int n,m,A,B,i,x,y,a[N];map<ll,ll>f; ll ans; void dfsl(int x,ll y){ if(x==m){f[y]++;return;} dfsl(x+1,y+a[x]); dfsl(x+1,y); } void dfsr(int x,ll y){ if(x==n){ans+=f[-y];return;} dfsr(x+1,y+a[x]); dfsr(x+1,y); } int main(){ freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); scanf("%d%d%d",&n,&A,&B); for(i=0;i<n;i++){ scanf("%d%d",&x,&y); a[i]=x*B-A*y; } m=n/2; dfsl(0,0); dfsr(m,0); ans--; printf("%lld",ans); }
H. Hamburgers
对于每个汉堡,$O(2^6)$枚举所有它可以满足的口味,然后对于每个人判断是否满足即可。
时间复杂度$O(m\sum a+2^6\sum b)$。
#include<cstdio> #include<cstring> #include<vector> using namespace std; const int N=55555; int n,m,i,j,k,x,ans[N],mx[N],b[N]; vector<int>a[N]; bool v[(1<<26)+5]; inline int get(){ static char s[1000]; scanf("%s",s); int t=0,len=strlen(s); for(int i=0;i<len;i++)t|=1<<(s[i]-'a'); return t; } inline void make(int x,int y){ for(int i=x;i;i=(i-1)&x)v[i]=y; } int main(){ freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); scanf("%d",&n); for(i=1;i<=n;i++){ scanf("%d",&k); while(k--){ x=get(); a[i].push_back(x); } ans[i]=1; } scanf("%d",&m); for(i=1;i<=m;i++){ scanf("%d",&k); for(j=1;j<=k;j++)b[j]=get(); for(j=1;j<=k;j++)make(b[j],1); for(j=1;j<=n;j++){ int t=0; for(x=0;x<a[j].size();x++)if(v[a[j][x]])t++; if(t>mx[j])mx[j]=t,ans[j]=i; } for(j=1;j<=k;j++)make(b[j],0); } for(i=1;i<=n;i++)printf("%d\n",ans[i]); } /* 5 1 a 3 a ba cb 3 vba d ba 3 ca da da 3 as ba af 2 4 abc abcd a a 2 abcdef abcdev */
I. Intricate path
留坑。
J. Jumps through the Hyperspace
显然到每个点的时间越早越好,对于每种传送门预处理出每种余数下的最优等待时间即可。
#include<cstdio> #include<algorithm> #include<vector> #include<queue> using namespace std; typedef pair<int,int>P; const int N=2010,inf=~0U>>1; int n,m,st,i,j,a[N],b[N],c[N],d[N],w[N][N]; int f[N]; char g[N][N],op[N]; priority_queue<P,vector<P>,greater<P> >q; inline void ext(int x,int y){ if(f[x]>y)q.push(P(f[x]=y,x)); } int main(){ freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); scanf("%d%d%d",&n,&m,&st); while(m--){ scanf("%s",op); int o=op[0]; scanf("%d%d%d%d",&a[o],&b[o],&c[o],&d[o]); for(i=0;i<c[o];i++){ w[o][i]=inf; for(j=0;j<c[o];j++)w[o][i]=min(w[o][i],(a[o]*(i+j)+b[o])%c[o]+d[o]+j); } } for(i=1;i<=n;i++)scanf("%s",g[i]+1); for(i=1;i<=n;i++)f[i]=inf; ext(1,st); while(!q.empty()){ P t=q.top();q.pop(); if(f[t.second]<t.first)continue; for(i=1;i<=n;i++)if(g[t.second][i]!='.') ext(i,t.first+w[g[t.second][i]][t.first%c[g[t.second][i]]]); } if(f[n]==inf)puts("-1");else printf("%d",f[n]-st); }
K. King’s island
暴力搜索出一个上凸壳,然后翻转拼接起来得到完整的多边形即可。
#include<stdio.h> #include<iostream> #include<string.h> #include<string> #include<ctype.h> #include<math.h> #include<set> #include<map> #include<vector> #include<queue> #include<bitset> #include<algorithm> #include<time.h> using namespace std; void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); } #define MS(x, y) memset(x, y, sizeof(x)) #define ls o<<1 #define rs o<<1|1 typedef long long LL; typedef unsigned long long UL; typedef unsigned int UI; template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; } template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; } const int N = 1010, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f; template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; } int casenum, casei; int n; struct B { int x, y; bool operator < (const B & b)const { //y/x > b.y/b.x return y * b.x > x * b.y; } }; B p[100000]; int g; int f[N][N][62]; struct A { int x, y, z; }; bool bingo[60]; vector<B>ans[60]; void getvt(int x, int y, int v, vector<B>&vt, int DX, int DY) { if(v == 0)return; int o = f[x][y][v]; if(f[x - p[o].x][y - p[o].y][v] == o) { getvt(x - p[o].x, y - p[o].y, v, vt, DX + p[o].x, DY + p[o].y); } else { vt.push_back({p[o].x + DX, p[o].y + DY}); getvt(x - p[o].x, y - p[o].y, v - 1, vt, 0, 0); } } void init() { for(int i = 1; i <= 200; ++i) { for(int j = i + 1; j <= 200; ++j)if(__gcd(i, j) == 1) { int W = (i * i + j * j); int w = sqrt(W); if(w * w == W) { p[++g] = {i, j}; p[++g] = {j, i}; } } } sort(p + 1, p + g + 1); //printf("%d\n", g); MS(f, 0); f[0][0][0] = 1; for(int i = 0; i <= 500; ++i) { for(int j = 0; j <= 500; ++j) { for(int v = 29; v >= 0; --v)if(f[i][j][v]) { // int k = f[i][j][v]; auto &it = f[i + p[k].x][j + p[k].y][v]; if(it == 0)it = k; // for(int k = f[i][j][v] + 1; k <= g; ++k) { auto &it = f[i + p[k].x][j + p[k].y][v + 1]; if(it == 0)it = k; } if(i == 0 || j == 0)continue; for(int u = 1; u + v <= 30; ++u)if(f[i][j][u] && f[i][j][u] != f[i][j][v]) { if(!bingo[u + v]) { bingo[u + v] = 1; vector<B>up, down; getvt(i, j, u, up, 0, 0); getvt(i, j, v, down, 0, 0); int x = i; int y = j; //printf("%d %d %d\n", u + v, up.size(), down.size()); //puts("up------------"); for(int r = 0; r < up.size(); ++r) { x -= up[r].x; y -= up[r].y; ans[u + v].push_back({x, y}); //printf("%d %d\n", up[r].x, up[r].y); } //puts("down------------"); for(int r = 0; r < down.size(); ++r) { x += down[r].x; y += down[r].y; ans[u + v].push_back({x, y}); //printf("%d %d\n", down[r].x, down[r].y); } //puts("ans------"); for(auto w : ans[u + v]) { //printf("%d %d\n", w.x, w.y); } int pasue = 1; } } } } } for(int i = 1;i <= 30; ++i) { //printf("%d\n", bingo[i]); } } int main() { freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); init(); while(~scanf("%d", &n)) { if(n == 3) { puts("0 0\n4 3\n-20 21"); continue; } for(auto it : ans[n]) { printf("%d %d\n", it.x, it.y); } } return 0; } /* 【trick&&吐槽】 【题意】 【分析】 【时间复杂度&&优化】 28 195 9 15 -116 178 4 20 21 1 -159 -236 -11 -92 6 5 20 50 3 -94 -16 -274 -236 18 -92 35 */
L. Lexica
无视同一行/同一列的两个格子的位置关系,只需要在它们不相同时将方案数乘$2$,如此一来只关心每一行/每一列有多少格子没满足。
设$f[i][j][S][k]$表示考虑到$(i,j)$,每一列剩余情况为$S$,第$i$行还有$k$个格子需要填充时的方案数,然后逐格转移即可。
时间复杂度$O(n3^n)$。
#include<cstdio> typedef unsigned long long ll; const int N=18,M=1600000; int n,m,all,i,j,k,x,y,z,A,B,C,S,o,p[N],mask,cnt[N]; char a[N][N]; int e; ll f[2][M][3],mul; int w[M]; inline void clr(){ for(int i=0;i<=mask;i++)for(int j=0;j<3;j++)f[e^1][i][j]=0; } inline void nxt(){ //for(int i=0;i<=mask;i++)for(int j=0;j<3;j++)f[i][j]=g[i][j]; } inline int get(int S,int x){ return S/p[x]%3; } void dfs(int x,int y,int z){ if(x==n){ w[y]=z; return; } for(int i=0;i<3;i++)dfs(x+1,y*3+i,z*2+(!!i)); } int main(){ freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); scanf("%d",&n); m=n+2; for(i=0;i<m;i++)scanf("%s",a[i]); mul=1; for(p[0]=i=1;i<N;i++)p[i]=p[i-1]*3; all=p[n]; for(i=1;i<=n;i++){ if(a[0][i]!='#'&&a[m-1][i]!='#'&&a[0][i]!=a[m-1][i])mul*=2; if(a[i][0]!='#'&&a[i][m-1]!='#'&&a[i][0]!=a[i][m-1])mul*=2; if(a[i][0]!='#')cnt[i]++; if(a[i][m-1]!='#')cnt[i]++; if(a[0][i]!='#')mask+=p[i-1]; if(a[m-1][i]!='#')mask+=p[i-1]; } dfs(0,0,0); f[0][mask][0]=mul; for(i=1;i<=n;i++){ clr(); int o=cnt[i]; for(A=0;A<=mask;A++)f[e^1][A][o]=f[e][A][0]; e^=1; for(j=0;j<n;j++)if(a[i][j+1]=='.'){ clr(); for(S=0;S<=mask;S++){ if(w[S]>>j&1)for(k=0;k<=o;k++)if(f[e][S][k])f[e^1][S-p[j]][k]+=f[e][S][k]; for(k=1;k<=o;k++)if(f[e][S][k])f[e^1][S][k-1]+=f[e][S][k]; } e^=1; } } printf("%llu",f[e][0][0]); } /* 5 ##ARRR# H.#.##S Y.....E O.#.#.E ##....E ###.#.E #XNT#A# */
M. Maximal paths
树形DP求出每个点内部从叶子往上、从上往下的最大数字串即可。需要手写高精度。
#include<cstdio> #include<algorithm> using namespace std; typedef unsigned long long ll; typedef __int128 lll; const int N=10000010,M=50; const ll MO=1000000000000000000ULL; int n,i;char a[N]; struct P{ ll v[3]; P(){v[0]=v[1]=v[2]=0;} P operator+(int b){ P c; for(int i=0;i<3;i++)c.v[i]=v[i]; c.v[0]+=b; for(int i=0;i<2;i++)if(c.v[i]>=MO){ c.v[i+1]+=c.v[i]/MO; c.v[i]-=MO; } return c; } P operator+(const P&b){ P c; for(int i=0;i<3;i++)c.v[i]=v[i]+b.v[i]; for(int i=0;i<2;i++)if(c.v[i]>=MO){ c.v[i+1]+=c.v[i]/MO; c.v[i]-=MO; } return c; } P operator*(int b){ P c; for(int i=0;i<3;i++)c.v[i]=v[i]*b; for(int i=0;i<2;i++)c.v[i+1]+=c.v[i]/MO,c.v[i]%=MO; c.v[2]%=MO; return c; } P operator*(const P&b){ P c; static lll f[3]; f[0]=f[1]=f[2]=0; for(int i=0;i<3;i++)if(v[i])for(int j=0;i+j<3;j++)if(b.v[j])f[i+j]+=(lll)v[i]*b.v[j]; for(int i=0;i<2;i++)if(f[i]>=MO)f[i+1]+=f[i]/MO,f[i]%=MO; if(f[2]>=MO)f[2]%=MO; for(int i=0;i<3;i++)c.v[i]=f[i]; return c; } void up(const P&b){//max= int i; for(i=2;~i;i--)if(b.v[i]!=v[i])break; if(i<0)return; if(b.v[i]<v[i])return; for(i=0;i<3;i++)v[i]=b.v[i]; } void write(){ int i=2; while(i&&!v[i])i--; printf("%llu",v[i]); for(int j=i-1;~j;j--)printf("%018llu",v[j]); puts(""); } }f[M],g[M],p[M],ans,ff,gg,mx[M]; int d[M]; unsigned int seed,base; void dfs(int x,int k){ f[k]=g[k]=mx[k]=P(); d[k]=0; for(int i=0;i<2;i++){ int y=x<<1|i; if(y>n)continue; dfs(y,k+1); ff=(f[k+1]*10)+((int)a[y]); gg=g[k+1]+(p[d[k+1]]*((int)a[y])); mx[k].up((ff*p[d[k]])+g[k]); mx[k].up((f[k]*p[d[k+1]+1])+gg); /*if(x==1){ puts("debug"); ff.write(); f[k].write(); }*/ f[k].up(ff); g[k].up(gg); d[k]=max(d[k],d[k+1]+1); /*if(x==1){ puts("debug"); ff.write(); f[k].write(); }*/ } /* printf("%d:\n",x); f[k].write(); g[k].write(); mx[k].write();*/ ans=ans+mx[k]; } int main(){ freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); scanf("%d%u",&n,&seed); base=(1U<<31)-1; p[0].v[0]=1; for(i=1;i<M;i++)p[i]=p[i-1]*10; for(i=1;i<=n;i++){ a[i]=((seed&base)>>16)%9+1; seed=seed*1103515245+12345; //printf("%d\n",a[i]); i and i/2 } dfs(1,0); ans.write(); }