Codeforces Round #251 (Div. 2)AK)

A、确定性数学计算,水,读题要快

 1 #include<iostream>
 2 #include<stdio.h>
 3 
 4 using namespace std;
 5 int N,d;
 6 int main(){
 7     while(~scanf("%d%d",&N,&d)){
 8         int cnt=0;
 9         for(int i=0;i<N;i++){
10                 int t;
11                 scanf("%d",&t);
12                 cnt+=t;
13         }
14         if (cnt+(N-1)*10>d){
15             printf("-1
");continue;
16         }
17         int ans=(N-1)*10/5+(d-(cnt+(N-1)*10))/5;
18         cout<<ans<<endl;
19 
20     }
21     return 0;
22 }
View Code

B、贪心,章节少的课先学,排序+贪心+long long 处理细节

 1 #include<iostream>
 2 #include<stdio.h>
 3 #include<algorithm>
 4 #include<stdlib.h>
 5 
 6 using namespace std;
 7 int n,s;
 8 int a[100005];
 9 
10 int main(){
11     while(~scanf("%d%d",&n,&s)){
12         for(int i=0;i<n;i++) scanf("%d",&a[i]);
13         sort(a,a+n);
14         long long ans=0;
15         s++;
16         for(int i=0;i<n;i++){
17             if (s>1) s--;
18             ans+=(long long)s*a[i];//在s前面加了long long 就过了,伤不起,应该是要强制转化成long long,不然后面两个int计算只保留了int部分
19         }
20         cout<<ans<<endl;
21     }
22     return 0;
23 }
View Code

注意:ans+=(long long)s*a[i];//在s前面加了long long 就过了,伤不起,应该是要强制转化成long long,不然后面两个int计算只保留了int部分

C、确定性数学证明(奇偶证明)+策略模拟 (很容易粗)

我的写法还是不是很好,下标算来算去,这道题一定要考虑到p-k==0的情况,不然会出错,

给自己出数据的时候,没有考虑到这个情况,比赛的时候可能就会跪了

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 using namespace std;
 5 int n,k,p,d;//p个偶数组合
 6 int a[100006],b[100006];
 7 int main()
 8 {
 9     while(~scanf("%d%d%d",&n,&k,&p)){
10         int cnt1=0,cnt2=0;
11         for(int i=0;i<n;i++){
12             int num;
13             scanf("%d",&num);
14             if (num % 2 == 0) a[cnt1++]=num;else b[cnt2++]=num;
15         }
16         int p1=p,p2=k-p;
17         if (cnt1+cnt2/2<p1){
18             cout<<"NO"<<endl;
19             continue;
20         }
21         if (cnt1>=p1){
22             if (cnt2<p2 || cnt2 % 2 != p2 % 2){
23                 cout<<"NO"<<endl;
24                 continue;
25             }
26             cout<<"YES"<<endl;
27             if (p2>0){
28                 for(int i=0;i<p1;i++){
29                     cout<<1<<" "<<a[i]<<endl;
30                 }
31                 cnt1=cnt1-p1;
32                 cout<<cnt1+(cnt2-p2)+1<<" ";
33                 for(int i=p1;i<p1+cnt1;i++){
34                     cout<<a[i]<<" ";
35                 }
36                 for(int i=0;i<(cnt2-p2)+1;i++){
37                     if (i==cnt2-p2){
38                         cout<<b[i]<<endl;
39                     }else cout<<b[i]<<" ";
40                 }
41                 for(int i=cnt2-p2+1;i<cnt2;i++){
42                      cout<<1<<" "<<b[i]<<endl;
43                 }
44             }else{
45                 cout<<cnt1-p1+1+cnt2;
46                 for(int i=0;i<cnt1-p1+1;i++) cout<<" "<<a[i];
47                 for(int i=0;i<cnt2;i++) cout<<" "<<b[i];
48                 cout<<endl;
49                 for(int i=cnt1-p1+1;i<cnt1;i++){
50                     cout<<1<<" "<<a[i]<<endl;
51                 }
52             }
53 
54             continue;
55         }else {
56             if (cnt2-(p1-cnt1)*2<p2 || (cnt2-(p1-cnt1)*2) % 2 != p2 %2 ){
57                 cout<<"NO"<<endl;
58                 continue;
59             }
60             cout<<"YES"<<endl;
61             for(int i=0;i<cnt1;i++){
62                 cout<<1<<" "<<a[i]<<endl;
63             }
64 
65             d=0;
66             if (p2>0){//这里是个大坑
67                 for(int i=cnt1;i<p1;i++){
68                     cout<<2<<" "<<b[d++]<<" "<<b[d++]<<endl;
69                 }
70             }else {//p2==0
71                 for(int i=cnt1;i<p1-1;i++){
72                     cout<<2<<" "<<b[d++]<<" "<<b[d++]<<endl;
73                 }
74                 cout<<cnt2-d<<" ";
75                 for(int i=d;i<cnt2;i++){
76                     if (i==cnt2-1) cout<<b[i]<<endl;else cout<<b[i]<<" ";
77                     d++;
78                 }
79             }
80             if (cnt2==d) continue;
81             if (cnt2 - d > p2){
82 
83                 cout<<cnt2-d-p2+1<<" ";
84                 for(int i=d;i<cnt2-p2+1;i++){
85                     if (i==cnt2-p2){
86                         cout<<b[i]<<endl;
87                     }else {
88                         cout<<b[i]<<" ";
89                     }
90                 }
91                 for(int i=cnt2-p2+1;i<cnt2;i++) cout<<1<<" "<<b[i]<<endl;
92             }else {//cnt2-d==p2
93                 for(int i=d;i<cnt2;i++) cout<<1<<" "<<b[i]<<endl;
94             }
95         }
96     }
97     return 0;
98 
99 }
View Code

 D、三分搜索+贪心+枚举(也可以排序+二分搜索(优化1/2的常数))

题目描述:给定A数组,n个数,给定B数组,m个数,

定义操作:一次任选数组,任选一个元素,可以增大或减少;

求一个最小操作数,使得改变后,A中最小的元素a大于等于B中最大的元素b。

方法就是上面所说的:

1、三分F(X):假设最终a=b=x,注意a和b肯定相等,因为我们是向中间取数的。不等没有相等步数少。

这样能确定x的范围,min(A)到max(B),因为我们肯定是增大A中元素,减小B中元素。

但是我不能证明是凹性的函数啊!!!

2、选定x,贪心的策略就定下来了:

if (a[i]<x) ans+=x-a[i];//尽可能用最小的步数达成目的

3、三分写法再总结:

(1)用t控制次数,不写while

(2)最终在[l,r]的范围内找到极值

(3)注意画图,尽可能地包含极值点

下面是别人的证明:

 1 #include<iostream>
 2 #include<stdio.h>
 3 #include<algorithm>
 4 #include<stdlib.h>
 5 #define LL long long
 6 using namespace std;
 7 int n,m;
 8 LL a[100005],b[100005];
 9 LL F(LL x)
10 {
11     //将A数组中的变成至少为x;(增加)
12     LL ans=0;
13     for(int i=0; i<n; i++) //可二分优化
14     {
15         if (a[i]<x) ans+=x-a[i];
16     }
17     //将A数组中的变成最多为x;(减少)
18     for(int i=0; i<m; i++)
19     {
20         if (b[i]>x) ans+=b[i]-x;
21     }
22     return ans;
23 }
24 int main()
25 {
26 //    freopen("out.txt","w",stdout);
27     while(~scanf("%d%d",&n,&m))
28     {
29         LL Min=1e12,Max=-1;
30         for(int i=0; i<n; i++)
31         {
32             scanf("%I64d",&a[i]);
33             Min=min(Min,a[i]);
34         }
35         for(int i=0; i<m; i++)
36         {
37             scanf("%I64d",&b[i]);
38             Max=max(Max,b[i]);
39         }
40         sort(a,a+n);
41         sort(b,b+m);
42         LL l=Min-1,r=Max+1;
43         for(int i=0; i<100; i++)
44         {
45             int m1=l+(r-l)/3,m2=r-(r-l)/3;
46             if (F(m1)<F(m2)) r=m2;
47             else l=m1;
48         }
49         LL ans=F(l);
50         for(LL i=l;i<=r;i++) ans=min(ans,F(i));
51         cout<<ans<<endl;
52     }
53     return 0;
54 }
View Code

 E、dp(关键是记忆化的思想)+乘法逆(数学考得好啊)

ps:题解:http://codeforces.com/blog/praveen123

推导过程太精妙了

DP递推的方法:

 1 #include <iostream>
 2 #include <string.h>
 3 #include <stdio.h>
 4 #include <vector>
 5 #include <map>
 6 #define LL long long
 7 #define Mod 1000000007
 8 using namespace std;
 9 //LL d[100005];//局部记忆化
10 //int dcas[100005],cas ;
11 LL Jie[100005];
12 LL inv[100005];
13 typedef pair<int,int>PAIR;
14 map<PAIR,int>MAP;
15 vector<int>Pri[100005];//使用变长数组,预处理约数
16 LL pow_mod(LL x,LL n){
17     LL ans=1;
18     while(n){
19         if (n & 1) ans =( ans * x ) % Mod;
20         x = (x*x) % Mod;
21         n=n/2;
22     }
23     return ans;
24 }
25 void init(){
26 //    memset(dcas,0,sizeof(dcas));
27     MAP.clear();
28     Jie[0]=1;
29     for(int i=1;i<=100000;i++) Jie[i]=(Jie[i-1]*i) % Mod;
30     for(int i=0;i<=100000;i++) inv[i]=pow_mod(Jie[i],Mod-2);
31 
32     for(int i=1;i<=100000;i++) Pri[i].clear();
33     for(int i=2;i<=100000;i++){//类似于筛选法,为每个数填上约数
34         for(int j=i;j<=100000;j+=i){
35             Pri[j].push_back(i);
36         }
37     }
38     return ;
39 }
40 LL calC(int n,int r){//C=n!/(r! * (n-r)!)
41     return ( Jie[n] * inv[r] % Mod )*inv[n-r] % Mod;
42 }
43 LL dp(int n,int f){
44     if (n<f) return 0;
45     if (n==f) return 1;
46     PAIR Key=make_pair(n,f);
47     if(MAP.count(Key)) return MAP[Key];
48 //    if (dcas[n]==cas) return d[n];
49 //    dcas[n]=cas;//这也是一种很好的办法,,兼顾空间(省去cas标记)、初始化用时、子结构用时
50     //但是面对极端重复数据就跪了
51     LL ans=calC(n-1,f-1);//得到C(n-1,f-1) //隔板法
52     LL sum=0;
53     for (int i=0;i<(int)Pri[n].size();i++){
54         int k=Pri[n][i];
55         sum+=dp(n/k,f);
56         sum = sum % Mod;
57     }
58     ans=(ans-sum + Mod) % Mod;
59     MAP[Key]=ans;
60     return ans;
61 }
62 int main(){
63     init();
64     int n,f,t;
65     scanf("%d",&t);
66     while(t--){
67         scanf("%d%d",&n,&f);
68         if (n<f){
69             puts("0");
70             continue;
71         }
72         LL ans=dp(n,f);
73         printf("%I64d
",ans);
74     }
75     return 0;
76 }
View Code
原文地址:https://www.cnblogs.com/little-w/p/3769864.html