A题:
从n个中取k个数字,使得这k个数字中,两两相加小于等于m。求最大的k。
考虑sort一遍n个数字,因为次大加上最大值如果小于m,那么说明这个最大是可以选取的,ans++。直到找到了一个次大和最大,相加大于了k,停止,因为只要这两个数字不大于k,集合里面的所有数字都不大于k了。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define up(i,a,n) for(int i=a;i<=n;i++)
const int maxn=1e5+10;
ll arr[maxn];
int main()
{
long long n,m;
scanf("%lld %lld",&n,&m);
up(i,1,n)scanf("%lld",&arr[i]);
if(n==1)
{
cout<<1<<endl;
return 0;
}
sort(arr+1,arr+1+n);
long long ans=0;
long long now=m;
for(int i=1;i<=n;i++)
{
if(arr[i]<=now)
{
ans++;
now=m-arr[i];
}
else break;
}
if(ans!=0)
printf("%lld",ans);
else printf("1");
return 0;
}
B题
模拟题。找到与当前给出来的日期相距最远的一个日期。
队友写的 ,大概这个意思吧。。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define up(i,a,n) for(int i=a;i<=n;i++)
const int maxn=150;
int d[12]={0,31,59,90,120,151,181,212,243,273,304,334};
int da[12]={31,28,31,30,31,30,31,31,30,31,30,31};
struct node
{
int month,day,num;
}arr[maxn];
int cmp(node a,node b)
{
return a.num<b.num;
}
int main()
{
int n;
scanf("%d",&n);
string s;
up(i,1,n)
{
cin>>s;
scanf("%02d-%02d",&arr[i].month,&arr[i].day);
arr[i].num=d[arr[i].month-1]+arr[i].day;
}
sort(arr+1,arr+1+n,cmp);
int now=arr[1].num+(365-arr[n].num)-1;
int now2=d[9]+28;
int now3=arr[1].num-now2;
if(now3<0)now3+=365;
int ans=1;
for(int i=2;i<=n;i++)
{
if(arr[i].num-arr[i-1].num-1>now)
{
now=arr[i].num-arr[i-1].num-1;
ans=i;
}
else if(arr[i].num-arr[i-1].num-1==now)
{
int d1=arr[i].num-now2;
if(d1<=0)d1+=365;
if(d1<now3)
{
ans=i;
now3=d1;
}
}
}
if(arr[ans].day!=1)printf("%02d-%02d",arr[ans].month,arr[ans].day-1);
else if(arr[ans].month!=1)
{
printf("%02d-%02d",arr[ans].month-1,da[arr[ans].month-2]);
}
else if(arr[ans].month==1&&arr[ans].day==1)
{
printf("12-31");
}
}
c题。
题目要求给一个长方形的箱子,无缝隙的可以放入n个111的cube,问最小表面加。
枚举边长,得到高,不断计算更新min值。
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
char ch = getchar(); int x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
int v;
int main()
{
v = read();
ll ans = 1e18;
upd(i, 1, v)
{
if (v%i == 0)
{
int chang = v / i;
upd(j, 1, chang)
{
if (chang%j == 0)
{
int kuan = chang / j;
ans = min(ans, (ll)(2 * i*j + 2 * kuan*i + 2*kuan*j));
}
}
}
}
cout << ans << endl;
return 0;
}
J题 数学题。
海伦公式的变形(题目保证了了有解)
对一般四边形的面积,扩展的婆罗摩笈多公式用到了四边形的对角和:
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
char ch = getchar(); int x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
double a, b, c, d;
int main()
{
cin >> a >> b >> c >> d;
double s = (a + b + c + d) / 2.0;
printf("%.8lf", (double)sqrt((s - a)*(s - b)*(s - c)*(s - d)));
return 0;
}
F题。
给出代价和每天赚的钱数,求最小天数,赚到k。
队友写的,用每天赚的除以需要赚的,玄学代码。
其实这道题二分就可以了,因为转的钱每天都在增加,所以某一天刚好可以了,后面所有天都可以了。
于是我们二分天数,对于每一个天数,带回去验证,赚的钱乘以天数-付出,大于零就记录下来
最后和需要赚的钱比较一下,就知道是否是我们要的了。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define up(i,a,n) for(int i=a;i<=n;i++)
const int maxn=1e5+10;
struct node
{
ll in,out,day;
}arr[maxn];
int cmp(node a,node b)
{
return 1.0*a.out/a.in>1.0*b.out/b.in;
}
int main()
{
long long n,m;
scanf("%lld %lld",&n,&m);
up(i,1,n)
{
scanf("%lld %lld",&arr[i].out,&arr[i].in);
}
sort(arr+1,arr+1+n,cmp);
double now=1.0*arr[1].out/(arr[1].in+m);
ll fz=arr[1].out;
ll fm=arr[1].in+m;
up(i,2,n)
{
ll dz=fz+arr[i].out;
ll dm=fm+arr[i].in;
double fs=1.0*dz/dm;
double fs1=1.0*arr[i].out/(arr[i].in+m);
if(fs>now&&fs>fs1)
{
fz=dz;
fm=dm;
}
else if(fs1>now&&fs1>fs)
{
fz=arr[i].out;
fm=arr[i].in+m;
}
now=1.0*fz/fm;
}
ll ans=ceil(1.0*fm/fz);
cout<<ans<<endl;
}
ps 这种类似于除法的规划问题,一般都用二分,这代码好玄学。。
G题,暴力模拟。
题意就是找出最小的移动代价,使得序列中ABC都是连在一起的。
枚举情况,有六种,abc,acb,cab,cba,bac,bca
但其实只有两种情况,abc和acb,因为他是个环,其他所有情况都是这两种情况的变形。
我们先把数组拉长。以保证环。
然后对于长度为len的字符串,不断尺取法加上差分思想去更新代价。
即,先对于原字符串,跑一遍代价,然后区间向有移动一格,然后对于每个小区间,0-a,a-a+b,a+b-a+b+c的端点,判断右移动一格后,出现的代价。
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
char ch = getchar(); int x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
int len;
string s;
string ss;
int A, B, C;
int judge(string s2)
{
int res = 0;
up(i, 0, len)
{
if (s2[i] != ss[i])res++;
}
return res;
}
int main()
{
len = read();
cin >> s;
up(i, 0, len)
{
if (s[i] == 'A')A++;
else if (s[i] == 'B')B++;
else C++;
}
ss = s;
s += ss;
string temp="";
up(i, 0, A)temp += 'A';
up(i, 0, B)temp += 'B';
up(i, 0, C)temp += 'C';
int ans = INF;
int ans1 = judge(temp);
ans = min(ans, ans1);
upd(i, 1, len-1)
{
if (s[i - 1] == 'A')ans1++;
if (s[i - 1 + A] == 'A')ans1--;
if (s[i - 1 + A] == 'B')ans1++;
if (s[i - 1 + A + B] == 'B')ans1--;
if (s[i - 1 + A + B] == 'C')ans1++;
if (s[i - 1 + A + B + C] == 'C')ans1--;
ans = min(ans, ans1);
}
temp.clear();
up(i, 0, A)temp += 'A';
up(i, 0, C)temp += 'C';
up(i, 0, B)temp += 'B';
int ans2 = judge(temp);
ans = min(ans, ans2);
upd(i, 1, len - 1)
{
if (s[i - 1] == 'A')ans2++;//整个区间右移动一格后,新的费用
if (s[i - 1 + A] == 'A')ans2--;
if (s[i - 1 + A] == 'C')ans2++;
if (s[i - 1 + A + C] == 'C')ans2--;
if (s[i - 1 + A + C] == 'B')ans2++;
if (s[i - 1 + A + B + C] == 'B')ans2--;
ans = min(ans, ans2);
}
cout << ans << endl;
return 0;
}
K题,任意删去有根树的一条边,使得任何点都可以到根节点。
贪心。
其实只要把叶子节点全部连接起来,就可以使得每个点都在某一个环内。
注意特判,如果根节点只有一个出度,那么根节点也要和叶子节点连接起来,不然删掉那一条边,根节点就gg了。
dfs找叶子节点记录下来。
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
char ch = getchar(); int x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
int val[100005], out[100005];
vector<int >g[100005];
vector<int >ans;
int n, h;
void dfs(int root, int f)
{
if (val[root] == 1)ans.push_back(root);
up(i, 0, g[root].size())
{
if (g[root][i] != f)
{
dfs(g[root][i], root);
}
}
}
int main()
{
n = read();
h = read();
int a, b;
up(i, 0, n - 1)
{
a = read();
b = read();
g[a].push_back(b);
g[b].push_back(a);
val[a]++;
val[b]++;
}
dfs(h, -1);
int temp = (ans.size()+1) / 2;
cout << temp << endl;
up(i, 0, ans.size() / 2)
{
cout << ans[i] << " " << ans[i + ans.size()/2] << endl;
}
if (ans.size() & 1)cout << ans.back() <<" "<<ans[0] << endl;
return 0;
}