A题
题目描述:
输入给出3个数x,y,n
判断从1——n的所有数字中,
如果n被x整除,输出Fizz
如果n被y整除,输出Buzz
如果n既被x整除又被y整除,输出FizzBuzz
否则输出n
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn=1e5+10;
int x,y,n;
int main(){
scanf("%d%d%d",&x,&y,&n);
for (int i=1;i<=n;i++){
if(i % x==0 && i % y==0) puts("FizzBuzz");
else if(i % x==0) puts("Fizz");
else if(i % y==0) puts("Buzz");
else printf("%d\n",i);
}
return 0;
}
B题
题目描述:
现在有2个候选人和n个投票人,每个人只能投两个候选人的其中一个。
现在给你四个数,三整数一小数n,v1,v2,w
表示一共的投票者,已经投了第一个人的人数和投了第二个人的人数v1和v2,求是否最后能决定第一个候选者的胜出
1.剩余的人投完票后,保证获胜概率>=w%,输出GET A CRATE OF CHAMPAGNE FROM THE BASEMENT!
2.不可能获胜(v2已经获得了半票了),输出RECOUNT!
3.不确定,输出PATIENCE, EVERYONE!
C(m,n)×0.5m(选中)×0.5n-m(未选中)=C(m,n)×0.5n
则如果C(n-v1-v2,n/2+1-v1) × 0.5n-v1-v2>w %,
则一定获胜
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
int T;
int n,v1,v2;
double w;
ll Cnm(int n,int m)//计算组合数C(n,m)
{
if(m>n/2)//根据组合公式,可以减少枚举量
m=n-m;
ll a=1,b=1;
for(int i=1;i<=m;i++)//顺序进行m次运算
{
a*=n+1-i;//计算前i项运算结果的分子a和分母 b
b*=i;
if(a%b==0)
{
a/=b;
b=1;
}
}
return a/b;
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d%d%d%lf",&n,&v1,&v2,&w);
double sum=0;
w/=100.0;
for (int i=n/2+1-v1;i<=n-v1-v2;i++){
sum+=1.0*Cnm(n-v1-v2,i)*pow(0.5,n-v1-v2);
}
if (v2 == n / 2 && n % 2 == 0) puts("RECOUNT!");
else{
if (sum>w)
puts("GET A CRATE OF CHAMPAGNE FROM THE BASEMENT!");
else if (v2 >= (n / 2 + 1)) puts("RECOUNT!");
else puts("PATIENCE, EVERYONE!");
}
}
return 0;
}
C题
题意:
有若干密码,每个密码都有一个称为正确密码的概率pi,现在问你从这串密码序列中找到正确密码的最小期望次数是多少
我们可以发现,对于密码序列,每次从剩下中选一个是C(n,1)=n的,n为当前还未选过的密码数,想要使得次数最少,则C(k,1)*pi每次要保证尽量小,因为C(k,1)是一个定值,于是我们将小的pi匹配大的C(k,1)就可以了,
于是答案为
∑ i = 1 n ( p i × C ( n + 1 − i , 1 ) ) ( p i 为 递 增 序 列 ) \sum_{i=1}^{n}{(p_i×C(n+1-i,1)) (pi为递增序列)}\\ i=1∑n(pi×C(n+1−i,1))(pi为递增序列)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
using namespace std;
const int maxn=600;
double pi[maxn];
string s[maxn];
int main(){
int n;
scanf("%d",&n);
for (int i=1;i<=n;i++){
cin>>s[i];
scanf("%lf",&pi[i]);
}
sort(pi+1,pi+n+1);
double ans=0.0;
for (int i=1;i<=n;i++){
ans+=pi[i]*(n+1-i);
}
printf("%.4f\n",ans);
return 0;
}
D题
题目描述:
有一个城市网络,有n个位置,m条街道,每两个位置之间可能有一条单向的街道,通过每一条街道需要一定的时间。有一家物流公司在0号节点,物流公司一天接到了C个委托人的物件,每个委托人在一个特定的位置。物流公司需要在规定时间送达,问至少需要多少辆车子才能把所有的物件在规定的时间送达。
输入图G(V,E)
计算所有的从仓库到委托人的最短路径
建立G’(V’,E’),V’包含起点和所有的委托人,且{<u,v>∈ V×V, d(0,u)+d(u,v)=d(0,v)}
G’是给一个DAG,于是答案是从0点开始的最小的不相交路径覆盖
解决方法:对题目给的图进行最大匹配,如最大匹配为ans,节点数量为n则最小路径为(n-ans)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#define ll long long
#define P pair<ll,int>
using namespace std;
const ll inf = 1e15;
const int N = 2e3 + 10;
vector<P> G[N];
vector<int> GG[N];
ll dis[N][N];
int n,m,C;
int a[N];
void dij(ll dis[],int s){
for(int i = 0;i < n;i++) dis[i] = inf;
dis[s] = 0;
priority_queue<P,vector<P>,greater<P> >q;
q.push(P(0,s));
while(!q.empty()){
P cur = q.top();q.pop();
int u = cur.second;
if(dis[u] < cur.first) continue;
for (int i=0;i<G[u].size();i++){
int v=G[u][i].second;
int w=G[u][i].first;
// auto now:G[u]
if(w + dis[u] < dis[v]){
dis[v] = dis[u] + w;
q.push(P(dis[v],v));
}
}
}
}
int match[1000];
int vis[1000];
bool dfs(int u){
vis[u] = 1;
// auto v:GG[u]
for(int i=0;i<GG[u].size();i++){
int v=GG[u][i];
int w = match[v];
if(w < 0 || !vis[w] && dfs(w)){
match[v] = u;
return true;
}
}
return false;
}
int Maxmatch(){
int ans = 0;
memset(match, -1, sizeof(match));
for(int i = 1;i <= C;i++){
memset(vis,0,sizeof(vis));
if(dfs(i)) ans++;
}
return ans;
}
int main(){
scanf("%d%d%d",&n,&m,&C);
for(int i = 1;i <= C;i++) scanf("%d",&a[i]);
for(int i = 0;i < m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
G[u].push_back(P(w,v));
}
dij(dis[0],0);
for(int i = 1;i <= C;i++){
int u = a[i];
dij(dis[u],u);
for(int j = 1;j <= C;j++){
if(a[j] != u && dis[0][u] + dis[u][a[j]] == dis[0][a[j]]) GG[i].push_back(j + C);
}
}
printf("%d\n",C - Maxmatch());
return 0;
}
H题
题目描述:
类似于2048的玩法,给你一串序列,问怎样往序列中加字母使得序列压缩之后最后可以变成一个数
做法:
Compress the numbers as much as you can.
Insert 2 next to each remaining 2.
Compress and repeat with 4’s.
Add 8’s at the end until the sum is a power of 2.
Hard part - keeping track of insertions relative to the original list.
Lists of size 1 are already done
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
string solve(){
string s;
cin>>s;
if(s.length()==1 || s=="22") return s;
for (int i=0,cnt=0;i<=s.length();i++){//s的长度动态变化
if((i==s.length() || s[i]>'2') && cnt&2) s.insert(i,"2");
else if((i==s.length() || s[i]>'4') && cnt&4) s.insert(i,"4");
cnt += s[i]-'0';
}
int tot=0;
for (int i=0;i<s.length();i++) tot+=s[i]-'0';
while(tot & (tot -1)){
tot+=8;
s+="8";
}
return s;
}
int main(){
int T;
cin>>T;
while(T--){
cout<<solve()<<endl;
}
return 0;
}
I题
题目描述:
给你n个大写都不同的杯子,
"string a"表示给你的是以a为半径的一个杯子
"b string"表示给你的是以b为直径的一个杯子
现在问你最后根据半径由小到大的杯子序列是什么
直接模拟即可
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <string>
using namespace std;
typedef long long ll;
int n;
struct node{
string str;
double r;
bool operator <(const node &rhs)const{ return r<rhs.r;}
}e[30];
int main(){
scanf("%d",&n);
getchar();
for (int i=1;i<=n;i++){
char s[30];
gets(s);
int len=strlen(s);
int k;
for (int j=0;j<len;j++){
if(s[j]==' '){
k=j;break;
}
}
if(s[0]>='0' && s[0]<='9'){
double sum=0;
int f=1;
for (int j=k-1;j>=0;j--){
sum+=f*(s[j]-'0');
f*=10;
}
e[i].r=sum/2;
for (int j=k+1;j<len;j++){
e[i].str+=s[j];
}
}
else{
for (int j=0;j<=k-1;j++){
e[i].str+=s[j];
}
double sum=0;
int f=1;
for (int j=len-1;j>=k+1;j--){
sum+=f*(s[j]-'0');
f*=10;
}
e[i].r=sum;
}
}
sort(e+1,e+n+1);
for (int i=1;i<=n;i++){
cout<<e[i].str<<endl;
}
return 0;
}
J题
题目描述:
给你一个字符串,你最终的任务是需要把他给显示出来。
你得到了一个类似于栈的东西
现在你可以做三件事(每次都算一次操作)
1.push,把一个字母放进栈顶
2.print,打印栈顶的字母
3.pop,将栈顶的字母弹出
问最少需要多少次操作你可以把这个字符串展示出来
做法:
显然,打印次数肯定为字符串的长度len次,
因此我们需要优化push和pop操作。
有这样一个方法:
对于每个字符,在我们打印完他之后,我们要么把他弹出要么推入一个新的字符在栈顶处,但显然这种方法太慢了。
所以我们考虑动态优化
我们设dp(i,j)表示最小的pop和push操作来打印出子串substr(i,j)
于是
最终的答案就是 len+dp(0,n-1)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <stack>
using namespace std;
const int maxn=210;
const int inf=0x3f3f3f3f;
int T;
int dp[maxn][maxn];
string s;
int solve(int i,int j){
if(i>j) return 0;
if(dp[i][j]==-1){
dp[i][j]=1+solve(i,j-1);
for (int k=i;k<j;k++){
if(s[k]==s[j]) dp[i][j]=min(dp[i][j],solve(i,k)+solve(k+1,j-1));
}
}
return dp[i][j];
}
int main(){
int T;
scanf("%d",&T);
getchar();
while(T--){
memset(dp,-1,sizeof(dp));
getline(cin,s);
int n=s.length();
int ans=n+2*solve(0,n-1);
cout<<ans<<endl;
}
return 0;
}