补题进度 7/11
J 夺宝奇兵
范围较小,直接枚举靠多少票赢即可,不够的票从小到大买
#include<bits/stdc++.h> #define ll long long const int maxn = 1005; using namespace std; struct node {ll id,val;int pos; }p[maxn],P[maxn]; bool vis[maxn]; bool cmp(node u,node v) {return u.val<v.val; } bool cmp2(node u,node v) {if(u.id==v.id) return u.val>v.val;return u.id<v.id; } int main() {int n,m;cin>>n>>m;for(int i=1; i<=m; i++){cin>>p[i].val>>p[i].id;p[i].pos=i;P[i]=p[i];}ll ans=1e18;sort(P+1,P+1+m,cmp);sort(p+1,p+1+m,cmp2);for(int i=1; i<=m; i++){memset(vis,0,sizeof(vis));int have=0;//当前有的票int need=i;//赢需要多少票int x=0;ll val=0;for(int j=1; j<=m; j++){if(p[j].id!=p[j-1].id) x=1;else x++;if(x>need) //别人票数大于你赢时需要的票数 {have++;val+=p[j].val;vis[p[j].pos]=1;}}if(have<=need) {for(int j=1; j<=m; j++){if(!vis[P[j].pos]){vis[P[j].pos]=1;have++;val+=P[j].val;if(have>need) break;}}}if(have>need)ans=min(ans,val);// cout<<i<<" "<<ans<<endl; }cout<<ans<<endl; }
F 爬爬爬山
我们很容易知道,当其他山大于第一座山+体力值时,此个山是到达不到的。所以我们在遇到这种情况的时候,我们直接把需要把减掉的花费建到边权就ok了,然后跑dij
#include<bits/stdc++.h> #define FIN freopen("input.txt","r",stdin) #define ll long long #define mod 998244353 const int maxn = 100005; using namespace std; int h[maxn],Next[maxn*20],head[maxn],To[maxn*20]; ll len[maxn*20],dis[maxn]; bool vis[maxn]; int cnt,n; inline void add(int u,int v,ll w) {Next[++cnt]=head[u];head[u]=cnt;To[cnt]=v;len[cnt]=w; } void dij() {for(int i=1;i<=n;i++)dis[i]=2e18;dis[1]=0;priority_queue<pair<ll,int> ,vector<pair<ll,int> > , greater< pair<ll,int> > >q;q.push(make_pair(0,1));while(!q.empty()){pair<ll,int> tmp=q.top();q.pop();int u=tmp.second;if(vis[u]) continue;vis[u]=1;for(int i=head[u];i!=-1;i=Next[i]){int v=To[i];ll d=len[i];// cout<<v<<" "<<len[i]<<endl;if(dis[v]>dis[u]+d){dis[v]=dis[u]+d;q.push(make_pair(dis[v],v));}}} } int main() {#ifndef ONLINE_JUDGEFIN;#endifmemset(head,-1,sizeof(head));int m;ll k;cin>>n>>m>>k;for(int i=1;i<=n;i++){cin>>h[i];}for(int i=1;i<=m;i++){int u,v;ll w;cin>>u>>v>>w;add(u,v,w+max(0LL,(h[v]-h[1]-k))*max(0LL,(h[v]-h[1]-k)));add(v,u,w+max(0LL,(h[u]-h[1]-k))*max(0LL,(h[u]-h[1]-k)));}dij();cout<<dis[n]<<endl; }
B 吃豆豆
数据是10*10的二维矩阵,数据特别小,我们直接对于每秒直接算暴力算此秒的值就好了
#include<bits/stdc++.h> #define FIN freopen("input.txt","r",stdin) #define ll long long #define mod 998244353 const int maxn = 100005; using namespace std; ll dp[11][11][20000]; int dir[5][2]={1,0,-1,0,0,-1,0,1,0,0}; bool vis[11][11][20000]; int T[11][11]; int main() {#ifndef ONLINE_JUDGEFIN;#endifint n,m,c;cin>>n>>m>>c;for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)cin>>T[i][j];int xs,ys,xt,yt;cin>>xs>>ys>>xt>>yt;vis[xs][ys][0]=1;for(int k=1;;k++){for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){if(!vis[i][j][k-1]) continue;for(int p=0;p<5;p++){int x=i+dir[p][0];int y=j+dir[p][1];if(x<1||x>n||y<1||y>m) continue;vis[x][y][k]=1;if(k%T[x][y]==0)dp[x][y][k]=max(dp[x][y][k],dp[i][j][k-1]+1);else dp[x][y][k]=max(dp[x][y][k],dp[i][j][k-1]);if(x==xt&&y==yt&&dp[x][y][k]>=c){cout<<k<<endl;return 0;}}}} }
C 拆拆拆数
直接拆成两个数(待证)
#include<bits/stdc++.h> #define FIN freopen("input.txt","r",stdin) #define ll long long #define mod 998244353 const int maxn = 3000005; using namespace std; ll prime[1005]; bool isprime[1005]; int main() {#ifdef ONLINE_JUDGE#else FIN;#endifint n,cnt=0;cin>>n;for(int i=2;i<=1000;i++){if(isprime[i]==0){prime[++cnt]=i;for(int j=1;j*i<=1000;j++){isprime[i*j]=1;}}}while(n--){ll a,b;cin>>a>>b;if(__gcd(a,b)==1)cout<<1<<"\n"<<a<<" "<<b<<"\n";else {for(int i=1;i<=cnt;i++){if(__gcd(a-prime[i],prime[i])==1&&(__gcd(prime[i],b-prime[i])==1)){cout<<2<<"\n";cout<<a-prime[i]<<" "<<prime[i]<<"\n";cout<<prime[i]<<" "<<b-prime[i]<<"\n";break;}}}} }
I 起起落落
题目是求 p[2k−1]>p[2k+1]>p[2k]的子序列有多少个。 我们定义dp[i] 表示前i个有多少个满足要求的子序列。
思路:dp[i]的值 可以由dp[1~i-2]得到 我们定义k代表可以使用的中间点
当a[1~i-2]>a[i]时我们可以直接算贡献 为(dp[]+1)*k 当a[2~i-2]<a[i]时我们都能讲此点作为中间点 k++;
#include<bits/stdc++.h> #define FIN freopen("input.txt","r",stdin) #define ll long long #define mod 1000000007 const int maxn = 2000+5; using namespace std; ll dp[maxn]; int a[maxn]; int main() {#ifndef ONLINE_JUDGEFIN;#endifint n;cin>>n;for(int i=1;i<=n;i++)cin>>a[i];int ans=0;for(int i=3;i<=n;i++) //枚举右端点 {int k=a[i]>a[i-1];for(int j=i-2;j>=1;j--){if(a[j]>a[i])dp[i]=(dp[i]+(dp[j]+1)*k)%mod;else if(a[j]<a[i])k++;}ans=(ans+dp[i])%mod;}cout<<ans<<endl; }
A 机器人
分类讨论即可 我们会发现我们最多传送两次即可走到所有点
最后可以分为两类:1.都在a区 答案直接为s点到最左点的特殊点和s到最右的特殊点的两倍
2.b区有 答案为1类答案再加上 2*k
要注意的是 a区 起点可作为转向点
详细可以参考如下博客:https://blog.csdn.net/CaprYang/article/details/86655459
代码同上~
E 流流流动
树形dp 按题意写即可~
#include<bits/stdc++.h> #define FIN freopen("input.txt","r",stdin) #define ll long long #define mod 1000000007 const int maxn = 300+5; using namespace std; int head[maxn],To[maxn*20],Next[maxn*20]; int f[maxn],d[maxn],dp[maxn][2],cnt; bool vis[maxn]; inline void add(int u,int v) {Next[++cnt]=head[u];head[u]=cnt;To[cnt]=v; }void dfs(int u,int fa) {vis[u]=1;dp[u][0]=0;dp[u][1]=f[u];for(int i=head[u];i!=-1;i=Next[i]){int v=To[i];if(v==fa) continue;dfs(v,u);dp[u][0]+=max(dp[v][1],dp[v][0]);dp[u][1]+=max(dp[v][0],dp[v][1]-d[min(u,v)]);} }int main() {#ifndef ONLINE_JUDGEFIN;#endifmemset(head,-1,sizeof(head));int n;cin>>n;for(int i=1;i<=n;i++)cin>>f[i];for(int i=1;i<=n;i++)cin>>d[i];for(int i=2;i<=n;i++){if(i&1) {add(i,3*i+1);add(3*i+1,i);}else {add(i,i/2);add(i/2,i);}}int ans=0;for(int i=1;i<=n;i++){if(!vis[i]){dfs(i,0);ans+=max(dp[i][0],dp[i][1]);}}cout<<ans<<"\n"; }
K 星球大战
unsolved
H 我爱割葱
unsolved
代更