C. Not Assigning
题意:给出一棵树,要求给边赋权值,使得长度小于等于2的路径权值和均为质数。
解:仔细想想质数都是奇数,奇数+奇数=偶数,那么长度为2的路径权值和要想仍为质数,必须包含2.那么一个结点就不能有两个以上儿子。再画一画发现只能是一条链,那好办了23232323这样子就好了。
D. Not Adding
长见识了。
题意:给出n个数,每个子集的最大公约数(数组中未出现)添加进去,问能添加多少个。( 1 ≤ n ≤ 106 )
解:首先排除暴力枚举。考虑分解因数,n√n,也会炸。思考未果,看题解。既然范围在1e6那么一个个枚举它会不会是gcd就可以了。。。能使它是gcd的只有它的倍数,复杂度 nlnn。判断方法:从它的倍数中找出2个能使得它为gcd而不是比它更大的数。介于gcd只会越求越小而且nlnn能过,所以全来一遍就好了。
代码:
#include<bits/stdc++.h> using namespace std; #define ll long long #define maxx 1000005 #define eps 0.00000001 #define inf 0x7fffffff //#define int long long int n; int vis[maxx]={0}; int gcd(int a,int b){ return b==0?a:gcd(b,a%b); } signed main() { // int T; // scanf("%d",&T); scanf("%d",&n); for(int i=1;i<=n;i++){ int t; scanf("%d",&t); vis[t]=1; } int ans=0; for(int i=1;i<maxx;i++){ if(vis[i]) continue; int t=0; for(int j=i;j<maxx;j+=i){ if(vis[j]) t=gcd(t,j); } if(t==i) ans++; } printf("%d\n",ans); return 0; }
E. Not Escaping
我真傻,真的。
题意:房子着火了(听说学校门口真着火了。。。),一个人要从 (1,1) 爬到 (n,m) 寻找救援。在第 i 层楼移动一个房间需要耗费 xi 点健康值。楼下到楼上之间有梯子,爬一次梯子增加 hi 点健康值。求最终最大的生命值。
解:看起来很简单的一道dp但WA了很多次。人家说两个窗口之间只有一个梯子,没说一个窗口只搭一个梯子。。。显然只有搭了梯子的房间是有用的,这样总房间个数是1e5而不是1e5*1e5,把起点和终点也加进来获得dp值。然后碰到这种值和左右两边有关的,每层从左到右更新,从右到左更新,最后把梯子的值递上去,over。写法学习了status里一位大佬的,超好看qwq
代码:
#include<bits/stdc++.h> using namespace std; #define ll long long #define maxx 100005 #define eps 0.00000001 #define inf 2e18 //#define int long long int n,m,k; ll x[maxx]; struct node{ int c,d,h; }; signed main() { int T; scanf("%d",&T); while(T--){ scanf("%d%d%d",&n,&m,&k); map<int,vector<node>> mp[n+1]; map<int,ll> dp[n+1]; for(int i=1;i<=n;i++) scanf("%lld",&x[i]); for(int i=1;i<=k;i++){ int a,b,c,d,h; scanf("%d%d%d%d%d",&a,&b,&c,&d,&h); mp[a][b].push_back(node{c,d,h}); dp[a][b]=inf; dp[c][d]=inf; } dp[1][1]=0;dp[n][m]=inf; for(int i=1;i<=n;i++){ ll pos=1,now=inf; for(auto it=dp[i].begin();it!=dp[i].end();it++){ auto [j,w]=*it; dp[i][j]=now=min(dp[i][j],now+x[i]*(j-pos)); pos=j; } pos=m;now=inf; for(auto it=dp[i].rbegin();it!=dp[i].rend();it++){ auto [j,w]=*it; dp[i][j]=now=min(dp[i][j],now+x[i]*(pos-j)); pos=j; } for(auto it=dp[i].begin();it!=dp[i].end();it++){ auto [j,w]=*it; for(auto [c,d,h]:mp[i][j]) dp[c][d]=min(dp[c][d],dp[i][j]-h); } } if(dp[n][m]>=1e18) printf("NO ESCAPE\n"); else printf("%lld\n",dp[n][m]); } return 0; }
PS:现在开map组已经可以mp[n+1]了,这样不会超时,否则不管是开里面开外面都会TLE的。
PSS:吐槽一下,发表的时候,