solve:4/11
补题:6/11
A 机器人
补题:zz
这是一道分类讨论的题目,有一个规律就是如果必须要从第一个区到第二个区,那么最多转区两次(1到2一次,2到1一次),然后分类讨论即可,只要细心一定能做出来。
//#pragma comment(linker, "/STACK:102400000,102400000") #include#include #include #include<string.h> #include<string> #include #include #include #include
B 吃豆豆
Code:pai爷
Thinking: pai爷 KK
dp[ i ][ j ][ k ]表示 i 行 j 列 在第 k 秒的时候吃到的最多的豆豆数量,从五个方向转移(上下左右加自己)。k的范围最大只有1018*10,然后用滚动数组滚动掉,就可以AC了。
补充:div1 1018变成了10^18,会有周期,尚未证明,k,k+t,k+2t。
#include#include #include #include #include using namespace std; int ans=0,n,m,c,now=0,X1,X2,Y1,Y2,f[3][20][20],t[20][20]; void solve(int a,int b,int c,int d,int k) { if(t[a][b]!=0 && (k%t[a][b]==0)) f[!now][a][b]=max(f[now][c][d]+1,f[!now][a][b]); else f[!now][a][b]=max(f[now][c][d],f[!now][a][b]); } int main() { scanf("%d%d%d",&n,&m,&c); for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) scanf("%d",&t[i][j]); scanf("%d%d%d%d",&X1,&Y1,&X2,&Y2); for(int k=0; k<=1; k++) for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) f[k][i][j]=-1; f[now][X1][Y1]=0; for(int k=1; k<=11000; k++) { for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) if(f[now][i][j]!=-1) { solve(i+1,j,i,j,k); solve(i-1,j,i,j,k); solve(i,j+1,i,j,k); solve(i,j-1,i,j,k); solve(i,j,i,j,k); if(f[!now][X2][Y2]>=c) ans=k; } if(ans) break; now=!now; } printf("%d\n",ans); }
C 拆拆拆数
unsolved
D 超难的数学题
unsolved
E 流流流动
补题:kk
树形dp,比赛没人做,以为是难题。
#include#include #include #include #define CLR(a,b) memset(a,b,sizeof(a)); using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const int maxn=10010; int head[maxn],tot,n; bool vis[maxn]; int f[maxn],d[maxn]; int dp[2][maxn]; struct edge{ int v,Next; }a[maxn<<2]; void init(){ tot=0,CLR(head,-1); CLR(vis,false); CLR(dp,0); } void addv(int u,int v) { a[++tot].v=v; a[tot].Next=head[u]; head[u]=tot; } void tdfs(int u,int fa){ int flag=0; vis[u]=1; dp[0][u]=0; dp[1][u]=f[u]; for(int i=head[u];i!=-1;i=a[i].Next) { int v=a[i].v; if(v==fa)continue; tdfs(v,u); flag=1; dp[0][u]+=max(dp[0][v],dp[1][v]); dp[1][u]+=max(dp[0][v],dp[1][v]-d[min(u,v)]); } } int main(){ cin>>n; init(); for(int i=1;i<=n;i++) { scanf("%d",&f[i]); } for(int i=1;i<=n;i++) { scanf("%d",&d[i]); } for(int i=2;i<=n;i++) { if(i%2==1) { addv(i,3*i+1); addv(3*i+1,i); } if(i%2==0){ addv(i,i/2); addv(i/2,i); } } int ans=0; for(int i=1;i<=n;i++) { if(vis[i]==0){ tdfs(i,0); ans+=max(dp[0][i],dp[1][i]); } } printf("%d\n",ans); }
F 爬山
Code:KK
Thinking:KK
对于一座山,如果要砍,就肯定要砍到(K+第一座山的高度),将这部分额外的花费加到边的权值上就好了,双向边要分开建,权值不一定一样,然后dijkstra跑一跑,水题。
1 #include2 #include 3 #include 4 #include<string.h> 5 #include<string> 6 #include 7 #include 8 #include 9 #include
G 双重矩阵
unsolved
H 我爱割葱
unsolved
I 起起落落
Code:pai爷
Thinking:pai爷
div 2 树状数组+dp思想 O(n*n*log(n))
1 #include2 #include 3 #include 4 #include 5 #include 6 #include 7 using namespace std; 8 const int P=1e9+7; 9 int n,p[2010],w[2010],c[10100],q[2010][2010]; 10 int ans=0; 11 inline int lowbit(int x){return x&-x;} 12 void add(int x,int y) 13 { 14 for(;x<=n;x+=lowbit(x)) c[x]=(c[x]+y)%P; 15 } 16 int sum(int x) 17 { 18 int tmp=0; 19 for(;x;x-=lowbit(x)) tmp=(tmp+c[x])%P; 20 return tmp; 21 } 22 int main() 23 { 24 scanf("%d",&n); 25 for(int i=1;i<=n;i++) scanf("%d",&p[i]); 26 for(int i=1;i<=n;i++) 27 for(int j=i+1;j<=n;j++) 28 { 29 if(p[i]<p[j]) 30 { 31 q[i][0]++; 32 q[i][q[i][0]]=j; 33 //printf("%d %d\n",i,j); 34 } 35 } 36 for(int i=n;i>=1;i--) 37 { 38 w[i]=sum(p[i]-1); 39 ans=(ans+w[i])%P; 40 //printf("%d\n",ans); 41 w[i]++; 42 for(int j=1;j<=q[i][0];j++) add(p[q[i][j]],w[q[i][j]]); 43 } 44 printf("%d\n",ans); 45 }
J 夺宝奇兵
Code:zz
Thinking:KK zz
div2:由于m最大只有一千,所以从(m+1)/2到1枚举最后我需要买的物品,每次和当前答案更新。如一个人的物品比自己需要买的多或一样多,那肯定先把多余这部分的全部买走,如果发现不够,那么就在剩下的所有里面挑最便宜的;如果发现买完那些比自己大的,就已经超出当前的值了,说明不合法,就不更新答案。用multiset完成以上操作。
div1:m变成一万,不能枚举,想到二分,发现中间有一段区间虽然都是合法的,但是并不是买的物品越少钱越少(买的物品多了,强制买的物品就少,然后不足的就可以从其他物品里挑最便宜的),所以不满足二分的性质,三分好像可以做(wls吐槽好像二字),标算是线段树?还不会。
1 //#pragma comment(linker, "/STACK:102400000,102400000") 2 #include3 #include 4 #include 5 #include<string.h> 6 #include<string> 7 #include 8 #include 9 #include 10 #include
K 星球大战
unsolved
建bfs树
训练总结:
KK: 简单dp听了pai爷的一些思路马上意会到正解。最短路看错样例,看清后秒解,然后oj的排名炸了,以为今天只能做两题,所以在梦游想题,后来发现J题数据量小,想了一下想到div2的正解,被zz优化了一下,刚好过了,自己写可能会wa一发(因为没有二分的性质,但是自己写可能会找到一个答案就直接break),以后训练要认真,很多题都是可以思考的,不到最后不要放弃。
pai爷:做题的时候缺少验证吧,不够认真对待题目,思路要清晰,想法很多,错误想法也很多。之后要大胆猜测以及大胆验证。
zz:一开局看到了B,感觉和以前做的一道题很像,想到可能是一个三重循环的dp,但是时间那一维和状态转移方程没想好,就没说,看其他题去了;后来oj出了问题,基本上没更新,题目基本上没什么思路,过了很久以后,kk跟我说了J题的暴力做法,我看了看n和m才一千,感觉行,后来在写的时候发现太暴力是要n^3的,就用multiset降到了n*n*log(n),刚好过(因为comp函数写错了wa了,哭了)。