----------------
A. Magic Numbers
一个神奇的数字是由1、14、144连接而成的,判断一个数字是不是神奇数字。
----
①没有连续3个以上的4。
②首位不能为4。
数据范围太大,最好按字符读入。
#include <iostream> #include <cstdio> #include <cstring> using namespace std; char c; int n,num; bool flag; int main() { flag=true; num=0; n=0; while (cin>>c) { if (n==0&&c!='1') { flag=false; break; } if (c!='1'&&c!='4') { flag=false; break; } if (c=='4') num++; else num=0; if (num>2) { flag=false; break; } n++; } if (flag) cout<<"YES"<<endl; else cout<<"NO"<<endl; return 0; }----------------
B. Ping-Pong (Easy Version)
两个数对(a,b)、(c,d),若c < a < d or c < b < d 则数对(a,b)到数对(c,d)存在一条有向边。
① 1 a b 表示添加数对(a,b)
② 2 a b 询问是否有一条路径由第a个数对到第b个数对。
----
按要求建边,dfs判断是否连通即可。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; int n; bool a[111][111]; int x[111],y[111]; bool vis[111]={0}; bool dfs(int u,int v) { vis[u]=true; if (u==v) return true; for (int i=0;i<n;i++) if (a[u][i]&&!vis[i]) if (dfs(i,v)) return true; return false; } int main() { int T; n=0; memset(a,0,sizeof(a)); cin>>T; while (T--) { int t; cin>>t; if (t==1) { cin>>x[n]>>y[n]; for (int i=0;i<n;i++) { if ((x[i]<x[n]&&x[n]<y[i])||(x[i]<y[n]&&y[n]<y[i])) a[n][i]=true; if ((x[n]<x[i]&&x[i]<y[n])||(x[n]<y[i]&&y[i]<y[n])) a[i][n]=true; } n++; } if (t==2) { int x,y; cin>>x>>y; memset(vis,0,sizeof(vis)); if (dfs(x-1,y-1)) cout<<"YES"<<endl; else cout<<"NO"<<endl; } } return 0; }----------------
C. Malek Dance Club
A组织的2^n个人与B组织的2^n配对跳舞。
配对规则为一个长度为n的二进制串x。
A组织的第i个人与B组织的第(i异或x)个人跳舞。
若有(a, b) (c, d)配对,若 a < c and b > d. 则有一个配对的复杂度。
给出x,问两个组织配对跳舞的复杂度。结果mod1000000007 。
----
有图有真相。。。
图中左右两侧的点为A、B两组织的人员i的二进制编号,上方的x为异或用的二进制串。
在配对的两个人之间连一条线,则配对复杂度即为交点的个数。
假设已经解决了二进制串x,现在要计算1x和0x的值。
此时已经计算出了f(x)的值。
由图观察可知:
①f(0x)=2*f(x)。
(设左右侧原来的编号为e,现在编号变为1e和0e,左0e和右0e配对,左1e和右1e配对,交点变为原来的2倍)
(而左侧0e和右侧1e之间并没有增加新交点,总交点数变为以前的2倍)
②f(1x)=2*f(x)+4^n。
(编号变为1e和0e交点变为以前的2倍,而左0e与右1e配对,左1e与右0e配对,左0e与右0e产生了2^n个新交点,同理左1e与右1e产生了2^n个新交点)
(共增加了4^n个交点)
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> #include <string> using namespace std; const int maxn=111; const int MOD=1000000007; long long f[maxn]; int n; string x; long long pw[maxn]; int main() { pw[0]=1; for (int i=1;i<=100;i++) { pw[i]=pw[i-1]*4%MOD; } while (cin>>x) { n=x.length(); f[n]=0; for (int i=n-1;i>=0;i--) { if (x[i]=='0') f[i]=2*f[i+1]; if (x[i]=='1') f[i]=2*f[i+1]+pw[(n-i-1)]; f[i]%=MOD; } cout<<f[0]<<endl; } return 0; }----------------
D.
Psychos in a Line
n个人排成1排,每个人有一个SAN值。
每一回合,若一个人SAN值大于右边人的SAN值,则右边的人被杀。
所有杀害同时发生。剩下的人重新排列。
问多少回合后没有杀害发生。
----
题解暂无。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <stack> #include <queue> #include <cmath> using namespace std; const int maxn=111111; const int INF=1e9+7; int f[maxn]; int a[maxn]; int n; stack<int>stk; int main() { int ans; while (cin>>n) { ans=0; while (!stk.empty()) stk.pop(); memset(f,0,sizeof(f)); for (int i=1;i<=n;i++) cin>>a[i]; f[0]=INF; stk.push(0); for (int i=1;i<=n;i++) { f[i]=1; while (!stk.empty()&&a[i]>a[stk.top()]) { f[i]=max(f[i],f[stk.top()]+1); stk.pop(); } stk.push(i); if (f[i]<INF) ans=max(ans,f[i]); } cout<<ans<<endl; } return 0; }----------------
E. Kalila and Dimna in the Logging Industry
Kalila和Dimna两个豺狼生活在一个巨大的丛林。有一天,他们为了赚钱加入了一个伐木厂。
伐木场的经理希望他们去树林里砍高度为a1,a2,a3…an的n课树。他们从一家商店里买了一台链锯。每次在编号为i的树上使用链锯,他们都能减少这棵树的一个单位高度。每次Kalila和Dimna使用链锯,他们需要重新对它充电。充电的成本依赖于已经被完全切断的树的编号id(一棵树高度为0时被完全切断)。如果被完全切断的树最大的编号为i(树一开始高度为ai),那么对链锯充电的成本为bi。如果没有树被完全切断,Kalila和Dimna不能对链锯充电。链锯在伐木开始之前已经充电。我们已知对于每个i<j,ai<aj并且bi>bj,而且bn=0、a1=1。Kalila和Dimna希望用最低的成本砍完所有的树木。
他们希望你来帮助他们,你会吗?
INPUT
第一行包含一个整数n (1 ≤ n ≤ 105),第二行包含n个整数a1,a2,a3…an (1 ≤ ai ≤ 109),第三行包含n个整数,b1,b2,b3….bn (0 ≤ bi ≤ 109)。
保证a1=1,bn=0,a1<a2<...<an并且b1>b2>…>bn
OUTPUT
输出只有一行,砍完所有树木的最低成本。
----斜率DP
令f[i]为完全砍断第i棵树的最低成本。
如果最后一棵被砍断的树的编号为j,则f[i]=f[j]+a[i]*b[j]。
因此f[i]=min(f[j]+a[i]*b[j]) ( j<i )
简单dp时间复杂度为O(N*N)会超时,使用斜率优化可以变为O(N)的复杂度。
/* //f[i]=min(f[j]+a[i]*b[j]) j<i //-a[i]*b[j]+f[i]=f[j] //令f[j]为y,b[j]为x,-a[i]为k,截距为dp[i] */ #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <string> #include <cmath> using namespace std; typedef long long LL; const int maxn=111111; LL a[maxn],b[maxn],f[maxn]; int n; int que[maxn*4]; int head,tail; //y1-y2 LL fun(int k1,int k2){ return f[k1]-f[k2]; } //y1-y2>=k*(x1-x2) bool cmp_head(int k1,int k2,int i){ return fun(k1,k2)>=-a[i]*(b[k1]-b[k2]); } //y1-y2/x1-x2>=y2-yi/x2-xi bool cmp_tail(int k1,int k2,int i){ return double(fun(k1,k2))/double(b[k1]-b[k2])>=double(fun(k2,i))/double(b[k2]-b[i]); } //y-kx LL dp_sol(int i,int j){return f[j]+a[i]*b[j];} //y1-y2/x1-x2 double k_sol(int i,int j){return double(f[i]-f[j])/double(b[i]-b[j]);} int main() { while (cin>>n) { memset(f,0,sizeof(f)); for (int i=0;i<n;i++) cin>>a[i]; for (int i=0;i<n;i++) cin>>b[i]; head=tail=0; que[tail++]=0; f[0]=0; for (int i=1;i<n;i++) { while (tail-head>1&&dp_sol(i,que[head])>=dp_sol(i,que[head+1])) head++; //while (tail-head>1&&cmp_head(que[head],que[head+1],i)) head++; f[i]=dp_sol(i,que[head]); while (tail-head>1&&k_sol(i,que[tail-1])>=k_sol(que[tail-1],que[tail-2])) tail--; //while (tail-head>1&&cmp_tail(que[tail-2],que[tail-1],i) ) tail--; que[tail++]=i; } cout<<f[n-1]<<endl; } return 0; }
----------------