总结
难度不算特别大,但是我是傻逼
T1 一眼贪心
T2 无脑暴力
T3 毫无头绪
T4 写不出来
(没有押好韵)
T1 地鼠游戏
题意: 有 $n$ 个物品 $a_i$,在 $t_i$ 秒之内选中 $a_i$ 个物品会获得 $v_i$ 的权值,求最大权值。
一眼贪心,跟那道 智力大冲浪 完全是一回事。把每个物品以 $v_i$ 为关键字排一遍顺序,然后枚举每一个 $a_i$ 找到一个时间点放进去,然后累加就完了。
然后我就写错了,特此贴出来警示自己。还没开 freopen(寄
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| #include<bits/stdc++.h> using namespace std; struct ele{ int t,v; double p; }a[100005]; bool cmp(ele a,ele b){ if(a.t==b.t) return a.v>b.v; return a.t<b.t; } int n,Time[5005],ans=0,cnt=1; int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i].t); for(int i=1;i<=n;i++){ scanf("%d",&a[i].v); a[i].p=a[i].v*1.0/a[i].t; } sort(a+1,a+1+n,cmp); for(int i=1;i<=n;i++){ if(a[i].t<cnt) continue; Time[cnt]=i; ans+=a[i].v; cnt++; } printf("%d\n",ans); return 0; }
|
鬼知道我这个贪心怎么写的
code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| #include<bits/stdc++.h> using namespace std; struct ele{ int t,v; double p; }a[100005]; bool cmp(ele a,ele b){ return a.v>b.v; } int n,Time[5005],ans=0,cnt=1; int main(){ freopen("game.in","r",stdin); freopen("game.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i].t); for(int i=1;i<=n;i++) scanf("%d",&a[i].v),ans+=a[i].v; sort(a+1,a+1+n,cmp); for(int i=1;i<=n;i++){ bool flg=false; if(!Time[a[i].t]){ Time[a[i].t]=1; flg=true; continue; } for(int j=a[i].t;j>=1;j--){ if(Time[j]==0){ flg=true; Time[j]=1; break; } } if(flg==false) ans-=a[i].v; } printf("%d\n",ans); return 0; }
|
考完之后就文思泉涌两分钟就写出来了
T2 数字加密
题意: 输入一个 $n$ ,找出所有使得 $x^{2}$ 后九位等于 $n$ 的 $x$ ,且 $x,n<1e^9$ , $x$ 的个数不超过4000
一看 $1e^9$ 就知道挨个枚举没戏,又去推了10分钟发现没什么好方法。作罢,只有打暴力,然后考虑剪个枝。
solution 1:
我在考场上写的解法,用了一点 $meet$ $in$ $middle$ 的想法,先考虑枚举前五位,将满足条件的记录下来,再拼凑后面四位 。
code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| #include<bits/stdc++.h> using namespace std; #define ll long long int mul[10]={0,1,4,9,6,5,6,9,4,1},tmp=0,cnt=0,t[4005]; char n[15]; void print(int x){ for(int i=1;i<=9;i++){ n[i]=x%10+'0'; x/=10; } for(int i=9;i>=1;i--) printf("%c",n[i]); cout<<endl; } int main(){ freopen("num.in","r",stdin); freopen("num.out","w",stdout); scanf("%s",n+1); for(int i=1;i<=9;i++){ tmp=(tmp<<1)+(tmp<<3)+n[i]-'0'; } for(int i=0;i<=99999;i++){ if(mul[i%10]!=tmp%10) continue; ll ans=(ll)i*i%100000; if(ans==tmp%100000) t[++cnt]=i; } for(int i=0;i<=9999;i++){ int k=i,x; for(int j=1;j<=cnt;j++){ x=k*100000+t[j]; ll ans=(ll)x*x%1000000000; if(ans==tmp) print(x); } } return 0; }
|
看到中间注释掉的那个特判了吗?
加了特判:100->70 (悲
solution 2:
利用 $DFS$ 暴力搜索枚举每一位数字,然后写一个小剪枝:搜到第k位时,保证前k位的平方取前 $k$ 位和目标的前 $k$ 位相同即可。
code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| #include<bits/stdc++.h> using namespace std; #define read(x) scanf("%d", &x) #define ll long long int ans[4010],tot=0,key; void dfs(int now,int k,int p){ if((ll)now*now % k != (ll)key % k ) return; if(10 == p) { ans[++tot] = now;return; } for(int i=0;i<10;i++) dfs(k*i + now ,k*10 ,p+1); } string int2str(int s){ string ret=""; for(int i=1;i<=9;i++,s=s/10) ret= (char)(s%10+'0')+ret; return ret; } int main(){ read(key); dfs(0,1,1); sort(ans+1,ans+tot+1); for(int i=1;i<=tot;i++) cout<< int2str(ans[i])<<"\n"; return 0; }
|
solution 3:
听说还有种很玄学的做法
通过完全平方公式可以知道 $n$ 和 $1e^9-n$ 的最后几位事相同的,所以只需要枚举一半就可以了。
code:
不写了
因为过于玄学和暴力,所以说明测试数据太水了。
T3 回文子串
题意: 给出 $k$ 条变换规则,其中 $x->y$ 且 $y->x$,求一个长度为 $n$ ,每个元素不超过 $m$ 的序列最长非连续回文子串的长度。
注意:$x->y$ 且 $y->x$,然后考场上就妹啥思路了
几个数可以看作一个联通块,然后用一个区间$dp$就完事了。状态转移方程:
code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| #include<bits/stdc++.h> using namespace std; int m,k,n,x,y,a[1005],fa[100005],f[1005][1005]; int find(int x){ if(fa[x]!=x) fa[x]=find(fa[x]); return fa[x]; } int dfs(int l,int r){ if(l>r) return 0; if(l==r) return 1; if(f[l][r]!=-1) return f[l][r]; if(find(a[l])==find(a[r])) f[l][r]=max(f[l][r],dfs(l+1,r-1)+2); else f[l][r]=max(dfs(l,r-1),dfs(l+1,r)); return f[l][r]; } int main(){ freopen("string.in","r",stdin); freopen("string.out","w",stdout); memset(f,-1,sizeof(f)); scanf("%d%d%d",&m,&k,&n); for(int i=1;i<=m;i++) fa[i]=i; for(int i=1;i<=k;i++){ scanf("%d%d",&x,&y); int fx=find(x),fy=find(y); if(fx!=fy) fa[fx]=fy; } for(int i=1;i<=n;i++) scanf("%d",&a[i]); cout<<dfs(1,n); return 0; }
|
T4 黑白图
一个 $n$ 个点 $m$ 条边构成的无向带权图。由一些黑点与白点构成。现在每个白点都要与他距离最近的黑点通过最短路连接,求这个最小代价。
很明显可以建立一个超级源点连接所有黑点,然后跑一遍最短路就可以求出到每个白点的最短路径。然后重建图跑一遍最小生成树,然后100->70。
正解应该是记录下每一个点的前驱边,将所有前驱边加在一起。
不知道为什么系统一直说我代码 $RE$ ,就先不贴代码了。