补题进度 7/11
J 夺宝奇兵
范围较小,直接枚举靠多少票赢即可,不够的票从小到大买
#include#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< } cout< endl; }
F 爬爬爬山
我们很容易知道,当其他山大于第一座山+体力值时,此个山是到达不到的。所以我们在遇到这种情况的时候,我们直接把需要把减掉的花费建到边权就ok了,然后跑dij
#include#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 int> ,vector int> > , greater< pair int> > >q; q.push(make_pair(0,1)); while(!q.empty()) { pair 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< if(dis[v]>dis[u]+d) { dis[v]=dis[u]+d; q.push(make_pair(dis[v],v)); } } } } int main() { #ifndef ONLINE_JUDGE FIN; #endif memset(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< endl; }
B 吃豆豆
数据是10*10的二维矩阵,数据特别小,我们直接对于每秒直接算暴力算此秒的值就好了
#include#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_JUDGE FIN; #endif int 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< endl; return 0; } } } } }
C 拆拆拆数
直接拆成两个数(待证)
#include#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; #endif int 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"<" "<"\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< " "< "\n"; cout< " "< "\n"; break; } } } } }
I 起起落落
题目是求 p[2k−1]>p[2k+1]>p[2k]的子序列有多少个。 我们定义dp[i] 表示前i个有多少个满足要求的子序列。
思路:dp[i]的值 可以由dp[1~i-2]得到 我们定义k代表可以使用的中间点