第一题数学公式推导,反正推完后就是(a*b)-a+b,没什么好说的,送分。
第二题懒得放题目,总而言之就是一道大模拟,判断循环,还挺麻烦的。。,但只要仔细都能打对。
主要是在每个循环判断能不能进,如果不能进就得停止累加时间复杂度,后面的E结束要对应前面的F,我是用了一个stack+结构体来判断这次能不能进循环,会不会停止,和更新答案了否(就是cifang有没有比之前+1),然后后面E结束循环时从栈顶开始减,就可以准确判断了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int t;
struct one
{
int x,st;
char c;
};
int pre(string x)
{
if(x[2] == '1') return 0;
else
{
int now = 4,num = 0;
while(isdigit(x[now]))
{
num = num * 10 + (x[now] - '0');
if(num > 50) return -1;
now++;
}
return num;
}
}
int pre2(string x)
{
int now = 0,num = 0;
while(isdigit(x[now]))
{
num = num * 10 + (x[now] - '0');
now++;
}
return num;
}
int main()
{
// freopen("complexity.in","r",stdin);
// freopen("complexity.out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0);
cin >> t;
while(t--)
{
int l,cifang = 0,Maxc = 0,cnt = 0;
bool wa = 0,err = 0; string str;
int stop = 0;
cin >> l;
set<char> s; stack<one> w;
cin >> str;
int base = pre(str);
if(base == -1) wa = 1;
for(int i = 1;i <= l;i++)
{
char a,b; string c,d; int nc,nd;
cin >> a;
if(a == 'F')
{
cnt++;
cin >> b >> c >> d;
if(err) continue;
if(s.count(b))
err = 1;
else s.insert(b);
int sto = stop,ci = cifang;
one tmp;
tmp.st = 0;
if(stop <= 0)
if(isdigit(c[0]) && !isdigit(d[0])) cifang++;
if(isdigit(c[0]) && isdigit(d[0]))
{
int nc = pre2(c),nd = pre2(d);
if(nc > nd) stop++;
}
else if(!isdigit(c[0]) && isdigit(d[0])) stop++;
tmp.c = b,tmp.x = 0;
if(sto != stop) tmp.st = 1;
if(cifang > ci) tmp.x = 1;
Maxc = max(Maxc,cifang);
w.push(tmp);
}
else {
cnt--;
if(cnt < 0)
err = 1;
if(err) continue;
one tmp = w.top();
w.pop();
cifang -= tmp.x;stop -= tmp.st;
s.erase(tmp.c);
}
}
if(cnt || err) cout << "ERR" << endl;
else
if(wa || (Maxc != base)) cout << "No" << endl;
else cout << "Yes" << endl;
}
return 0;
}
第三题就比较难了,又改了将近一下午orz。
这道题运用的思想和最短路计数的思想差不多,但是题目当中还允许不超过最短路长度K的路径,那么就需要在最短路计数上稍作变通才可以:
- 当然和最短路计数的套路一样,我们需要知道最短路到底是多少才可以判断某条路径是否满足要求,就先用SPFA算法来求一下最短路。
- 知道最短路之后我们怎么求解满足路径的条数呢?假想一下我们现在从起点开始走——由于我们已经使用SPFA大法来完成了求最短路的使命,我们自然而然的就维护出来了一个d数组(d[i]表示i点到起点的最短距离)这种功能就可以告诉我们当前所走的路是否有“冤枉路”了。解释:“冤枉路”是指从A点至B点所走的路径不是最短路,也就是说一共允许你走K冤枉路的长度,每走一次冤枉路都会消耗这个余额。
- 通过想象这个过程就能知道前面你的选择会对后面有影响,很自然的想到dp求解,dp(i,j)就表示你当前在i点,还允许你走j容量的“冤枉路”。
- 那什么时候有无穷多条合法路线呢?首先肯定是在路径里出现了环。(解释:因为简单路线肯定是有限条,无穷的肯定是有环)题目里提到了0边,这就使我们进一步想到0环——如果这个环不是零环,那肯定就不是在最短路上面了(何必绕着一点跑到黑呢!)肯定就会消耗“冤枉路”容量,就不可能是有限条。所以如果有0环出现,判断-1即可。
一些注意事项
- 虽然1号点一定能走到n号点,但是公园中有些点可能无法到达N,所以通过建立反向图的方式反向SPFA来排除那些无法到终点的点,把能到终点的点alive[i]值标为1即可,在dp的时候把alive值为0的点跳过即可
- 本题有多组数据,请大家一定要记得清空数组!
#include<bits/stdc++.h> using namespace std; #define ll long long const int MAXN = 1e5 + 5; const int MAXM = 2e5 + 5; const int INF = 0x7fffffff; int p; int T,n,m,k; int ans = 0; int head[MAXM*2],rhead[MAXM*2],cnt = 0,rc = 0; int dis[MAXN],rdis[MAXN]; int dp[MAXN][55]; bool vis[MAXN][60],alive[MAXN]; void read(int &x) { int f=1;x=0;char s=getchar(); while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();} while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();} x*=f; } struct edge { int next,to,w; }e[MAXM*2],r[MAXM*2]; void add(int u,int v,int w) { e[++cnt].next = head[u]; e[cnt].to = v; e[cnt].w = w; head[u] = cnt; } void radd(int u,int v,int w) { r[++rc].next = rhead[u]; r[rc].to = v; r[rc].w = w; rhead[u] = rc; } int dfs(int a,int b) { if(b < 0) return 0; if(vis[a][b] == 1) return -INF; if(dp[a][b] != -1) return dp[a][b]; vis[a][b] = 1; int cnt = 0; if(a == n) cnt++; for(int i = head[a];i;i = e[i].next) { int to = e[i].to; int w = e[i].w; int u = dis[to] - dis[a]; if(alive[to] == 0) continue; int wgt = dfs(to,b-(w-u)); if(wgt == -INF) return -INF; cnt = (cnt + wgt) % p; } dp[a][b] = cnt % p; vis[a][b] = 0; return cnt; } int q[MAXM*4],h,t; void spfa() { memset(q,0,sizeof q); h = t = 0; q[++t] = 1; dis[1] = 0; while(h != t) { int x = q[++h]; for(int i = head[x];i;i = e[i].next) { int to = e[i].to,w = e[i].w; if(dis[x] + w < dis[to]) { dis[to] = dis[x] + w; q[++t] = to; } } } } void rspfa() { memset(q,0,sizeof q); h = t = 0; q[++t] = n; alive[n] = 1; while(h != t) { int x = q[++h]; for(int i = rhead[x];i;i = r[i].next) { int to = r[i].to; if(alive[to] == 0) { alive[to] = 1; q[++t] = to; } } } } int main() { read(T); while(T--) { cnt = 0; rc = 0; read(n);read(m);read(k);read(p); for(int i = 1;i <= n;i++) { head[i] = 0;rhead[i] = 0; alive[i] = 0; for(int l = 0;l <= k;l++) { dp[i][l] = -1; vis[i][l] = 0; } } for(int i = 1;i <= m;i++) { int x,y,w; read(x);read(y);read(w); add(x,y,w); radd(y,x,w); } // memset(dis,0x3f,sizeof dis); for(int i = 2;i <= n;i++) dis[i] = INF; spfa(); rspfa(); int ans = dfs(1,k); if(ans == -INF) printf("%d\n",-1); else printf("%d\n",ans); } return 0; }