题目链接:https://ac.nowcoder.com/acm/contest/3003#question
emmm,没什么好说的,心理战。。。不交一发就不会知道这样确实是对的。。。
题目说明:
A.做游戏 B.排数字 C.算概率 D.数三角
(水题) (思维) (期望DP)(思维,勾股定理)
E.做计数 F.拿物品 G.判正误 H.施魔法
(思维) (贪心) (类hash) (DP)
I.建通道 J.求函数
(思维) (线段树)
A.做游戏
题目大意:牛牛和 牛可乐进行了多轮游戏, 牛牛总共出了 A 次石头,B 次剪刀,C 次布;牛可乐总共出了 X 次石头,Y 次剪刀,Z 次布。 你需要求出 牛牛最多获胜多少局。
示例
输入
114514 0 0 0 114514 0
输出
114514
没什么好说的,水题,每次取相克的最小值就好了,即$ans=min(A,Y)+min(B,Z)+min(C,X)$。
以下是AC代码:
#includeusing namespace std; typedef long long ll; int main(int argc, char const *argv[]) { ll a,b,c,x,y,z; cin>>a>>b>>c; cin>>x>>y>>z; ll sum=0; sum+=min(a,y); sum+=min(b,z); sum+=min(c,x); cout< endl; return 0; }
B.排数字
题目大意:给你一个数字字符串,让你打乱顺序,问你最多有多少个不同的子串为616
示例
输入
11 11451419266
输出
1
也没什么好说的,我们看一下$6161616$就知道这是最多的情况,那么6的数量会比1多1个。。所以我们统计一下1的个数和6的个数就好了。
以下是AC代码:
#includeusing namespace std; typedef long long ll; const int mac=2e5+10; char s[mac]; int main(int argc, char const *argv[]) { int n; scanf ("%d",&n); scanf ("%s",s+1); int one=0,six=0; for (int i=1; i<=n; i++){ if (s[i]=='1') one++; else if (s[i]=='6') six++; } if (six>=one+1) printf("%d\n",one); else { if (six>=2) printf("%d\n",six-1); else printf("0\n"); } return 0; }
C.算概率
题目大意:有n到题,每道题答对的概率为$p^{i}$问你恰好答对$0,1...n$题的概率,请对$1e9+7$取模
示例
输入
1 500000004
输出
500000004 500000004
这里给出的n个概率是在模$1e9+7$意义下的
看一下题目,应该是期望DP,然后再看一下数据范围。。。$n<=2000$,那么应该是$n^{2}$算法,那么我们就设$dp[i][j]$这个为一个状态,那么他具体代表什么意思呢?肯定有一个是答对的题目数量,我们将它放在$j$位置,那么很明显$i$就代表了已经答的题目数量。
那么怎么状态转移呢?正在答的这一题可能答对也可能答错,那么也就是说$dp[i][j]=dp[i-1][j]*(1-p)+dp[i-1][j-1]*p$
以下是AC代码:
#includeusing namespace std; typedef long long ll; const int mac=2e3+10; const int mod=1e9+7; ll dp[mac][mac],a[mac]; int main(int argc, char const *argv[]) { ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); int n; cin>>n; for (int i=1; i<=n; i++) cin>>a[i]; dp[0][0]=1; for (int i=1; i<=n; i++){ dp[i][0]=dp[i-1][0]*((1-a[i]+mod)%mod)%mod; for (int j=1; j<=i; j++){ dp[i][j]=dp[i-1][j]*((1-a[i]+mod)%mod)%mod; dp[i][j]+=dp[i-1][j-1]*a[i]%mod; dp[i][j]%=mod; } } for (int i=0; i<=n; i++) cout< ' '; cout<<endl; return 0; }
D.数三角
题目大意:给你n(n<=500)个点,求能构成多少个钝角三角形
输入
3 0 0 -1145 1 1 0
输出
1
emmm,就是用到了勾股定理,一个直角三角形$c^{2}=a^{2}+b^{2}$,我们将斜边延长一些,那么不就变成了钝角了吗。
以下是AC代码:
#includeusing namespace std; typedef long long ll; const int mac=600; struct node { int x,y; }pt[mac]; ll dist(int p1,int p2) { ll x1=pt[p1].x,x2=pt[p2].x; ll y1=pt[p1].y,y2=pt[p2].y; ll dis=(x1-x2)*(x1-x2)+(y1-y2)*(y1-y2); return dis; } int angle(ll mx,ll mid,ll mi) { double s1=sqrt(mx*1.0),s2=sqrt(mid*1.0),s3=sqrt(mi*1.0); if (s1 return 1; return 0; } int ok(int id1,int id2,int id3) { ll eg1=dist(id1,id2); ll eg2=dist(id1,id3); ll eg3=dist(id2,id3); ll mx=max(eg1,max(eg2,eg3)); ll mi=min(eg1,min(eg2,eg3)); ll mid=eg1+eg2+eg3-mx-mi; if (!angle(mx,mid,mi)) return 0; if (mx>mi+mid) return 1; return 0; } int main(int argc, char const *argv[]) { int n; scanf ("%d",&n); for (int i=1; i<=n; i++){ scanf ("%d%d",&pt[i].x,&pt[i].y); } int ans=0; for (int i=1; i<=n; i++) for (int j=i+1; j<=n; j++) for (int k=j+1; k<=n; k++){ if (ok(i,j,k)) ans++; } printf("%d\n",ans); return 0; }
E.做计数
题目大意:给你一个n(<=4e7)问你有多少个不同的正整数三元组$(i,j,k)$满足$\sqrt{i}+\sqrt{j}=\sqrt{k}$且$i*j<=n$
输入
1
输出
1
我们做个变形就出来了,两边同时平方:$i+j+2\sqrt{ij}=k$那么要维持正整数,$ij$必须是平方数,即$\sqrt{ij}$是个整数。那么我们只需要枚举1到$\sqrt{n}$设为$i$然后找$i^{2}$的因子就好了,复杂度是$O(\sqrt{n}*\sqrt{n})$
以下是AC代码:
#includeusing namespace std; int solve(int x) { if (x==1) return 1; int m=sqrt(x); int sum=1; for (int i=1; i ){ if (x%i==0) sum+=2; } return sum; } int main(int argc, char const *argv[]) { int n; cin>>n; int m=sqrt(n); long long ans=0; for (int i=1; i<=m; i++){ ans+=solve(i*i); } cout< endl; return 0; }
F.拿物品
题目大意:给你n(n<=2e5)个物品,每个物品有$a,b$两种属性,牛牛先选,然后是牛可乐,一直循环下去。他们都希望最大化自己与对方得分的差,问你他们拿的分别是那些物品
示例
输入
3 8 7 6 5 4 2
输出
1 3 2
实际上就是按照$(a+b)$的值贪心。至于为什么,出题人很良心的说明了:
假设物品已经被选完,此时 牛牛选择的物品 $A $属性的价值和是$ N $, 牛可乐选择的物品 $B$ 属性价值和是$ M $。
如果 牛牛的$ (a_{1},b_{1}) $物品与 牛可乐的$ (a_{2},b_{2}) $交换,则 $N′=N−a_{1}+a_{2},M′=M+b_{1}−b_{2}$
对于 牛牛(目标是最大化$ N−M $)来说会变得更优仅当 $a_{1}+b_{1}
对于 牛可乐也一样。所以两人都会优先选择 $a_{i}+bi_{i}$ 最大的物品。