已写:A、C、D、G、H、K、L、M
A - World Final? World Cup! (I)
题目链接:World Final? World Cup! (I)
算法标签:【模拟】
思路:根据题目大意,进行模拟。
需注意特殊数据:1000000000、0100000000、0101000000
答案为10、9、7
代码:
#include <iostream>
using namespace std;
void solve()
{
string str;
cin >> str;
str = "?" + str;
int x = 0,y = 0;//分别表示当前本队进入的球数
int cntx = 5,cnty = 5;//分别表示本队还剩余的次数
for(int i = 1;i <= 10;i ++)
{
if( i%2 ) //奇数位的时候,为x队进球
{
cntx --;
if(str[i] == '1')
x ++;
}
if( !(i%2) )//偶数位的时候,为y队进球
{
cnty --;
if(str[i] == '1')
y ++;
}
if((x > y+cnty) || (y > x+cntx) )
//判断 如果一队现有的分数大于另一队现有的分数与还剩的次数和,那么第一队获胜,直接输出
{
printf("%d\n",i);
return ;
}
}
printf("-1\n");
}
int main()
{
int T;
cin >> T;
while(T --)
solve();
return 0;
}
B - World Final? World Cup! (II)
题目链接:World Final? World Cup! (II)
留坑
C - 现在是,学术时间 (I)
题目链接:现在是,学术时间 (I)
算法标签:【贪心】【排序】【模拟】
思路1@eyuhaobanga:贪心做法。每个教授发自己的论文,当该论文的引用量为1是,那么ans++。
代码1:
#include <iostream>
using namespace std;
const int N = 1e5+10;
int a[N];
void solve()
{
int n;
cin >> n;
int ans = 0;
for(int i = 1;i <= n;i ++)
{
cin >> a[i];
if(a[i] > 0) //每个教授发自己的论文,当该论文的引用量为 1 时,那么ans++。
ans ++;
}
cout << ans << endl;
}
int main()
{
int T;
cin >> T;
while(T --)
solve();
return 0;
}
思路2:排序+模拟做法。先将教授按照所发表的论文的引用量从小到大进行排序,然后从头开始遍历,如果引用量为0的话,直接跳过;当引用量为1时,ans++;当引用量大于1时,假设此时引用量为x,在第i个位置,如果没有超出现有教授的论文即if(i+x-1<n) ans+=x-1
,如果超出了,剩下的自己发表自己的论文。
代码2:
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5+10;
int a[N];
void solve()
{
int n;
cin >> n;
for(int i = 1;i <= n;i ++)
cin >> a[i];
sort( a+1 , a+n+1 );
int ans = 0;
for(int i = 1;i <= n;i ++)
{
if(a[i] == 0) //如果引用量为0的话,直接跳过;
continue;
if(a[i] == 1) // 当引用量为1时,答案+1,表示该教授发表自己的论文
{
ans ++;
continue;
}
int cnt = a[i] - 1; // 第i个教授需要发表cnt篇论文,并且每篇引用量都大于cnt
if(i + cnt > n) // 第i个教授找不到cnt篇论文,剩下教授发表自己的论文,答案+剩下的教授数量
{
ans += n - i + 1;
break;
}
else // 第i个教授可以找到cnt篇论文,答案+论文至少的引用量,i跳转到还没发表论文的位置
{
ans += cnt;
i += cnt - 1;
}
}
printf("%d\n",ans);
}
int main()
{
int T;
cin >> T;
while(T --)
solve();
return 0;
}
D - 现在是,学术时间 (II)
题目链接:现在是,学术时间 (II)
算法标签:【计算几何】
思路:
我们可以根据给出的(x,y),将整个坐标划分为四个区域。
当(xp,yp)位于不同的区域中时,会有不同的情况。
- (xp,yp)在第一区域时,需要计算出(xp,yp)与A,B,C,D四个不同的点构成的矩形进行计算
- (xp,yp)在第二区域时,(xp,yp)与A,B两点可以构成最符合题目的矩形
- (xp,yp)在第三区域时,(xp,yp)与**(0,0)点**可以构成最符合题目的矩形
- (xp,yp)在第四区域时,(xp,yp)与A,D两点可以构成最符合题目的矩形
代码:
#include <iostream>
using namespace std;
typedef long long ll;
ll x , y , xp , yp;
void solve()
{
scanf("%lld%lld%lld%lld",&x,&y,&xp,&yp);
double res = 0;
if(xp <= x && yp <= y) // 在第一区域
{
res = max(xp * yp / (double) (x * y) , // (xp,yp)与 A(0,0) 构成的矩形
xp * (y - yp) / (double) (x * y) ); // (xp,yp)与 D(0,y) 构成的矩形
res = max(res , (x - xp) * yp / (double) (x * y) );// (xp,yp)与 B(x,0) 构成的矩形
res = max(res , (x - xp) * (y - yp) / double(x * y) );// (xp,yp)与 C(x,y) 构成的矩形
printf("%.10f\n",res);
return ;
}
if(xp <= x) // 在第二区域
{
res = max(xp * y / (double)(x * y + xp * (yp - y)) , // (xp,yp)与 A(0,0) 构成的矩形
(x - xp) * y / (double)(x * y + (x - xp) * (yp - y)));// (xp,yp)与 B(x,0) 构成的矩形
printf("%.10f\n",res);
return ;
}
if(yp <= y) // 第四区域
{
res = max(x * yp / (double)(x * y + yp * (xp - x)) , // (xp,yp)与 A(0,0) 构成的矩形
x * (y - yp) / (double)(x * y + (y - yp)*(xp - x)));// (xp,yp)与 D(0,y) 构成的矩形
printf("%.10f\n",res);
return ;
}
// 第三区域
res = x * y / (double) (xp * yp); // (xp,yp)与 A(0,0) 构成的矩形
printf("%.10f\n",res);
}
int main()
{
int T;
cin >> T;
while(T --)
solve();
return 0;
}
E - 鸡算几何
题目链接:鸡算几何
留坑
F - 鸡玩炸蛋人
题目链接:鸡玩炸蛋人
留坑
G - 鸡格线
题目链接:鸡格线
算法标签:【stl】【线段树】【并查集】
思路@FriedChicken:有这样的一个性质:f(x)经过不多次数的操作会收敛到一个不变的值f(x) = x
,此时x有三个,分别为0、99、100
代码:
#include <iostream>
#include <cmath>
#include <set>
using namespace std;
typedef long long ll;
const int N = 100010;
ll n , m , a[N] , ans;
set<int> st;
ll fun(ll x)
{
return round(sqrt(x)*10);
}
int main()
{
scanf("%lld%lld",&n,&m);
for(int i = 1;i <= n;i ++)
{
scanf("%lld",&a[i]);
ans += a[i];
if(fun(a[i]) != a[i])
st.insert(i);
}
st.insert( n+1 );
int op , l , r , k;
for(int i = 1;i <= m;i ++)
{
scanf("%d",&op);
if(op == 1)
{
scanf("%d%d%d",&l,&r,&k);
int pos = l;
while(true)
{
int next = (*st.lower_bound(pos));
if(next > r)
break;
for(int j = 1;j <= min(k,20);j ++)
{
ans -= a[next];
a[next] = fun(a[next]);
ans += a[next];
}
if(fun(a[next]) == a[next])
st.erase(next);
pos = next + 1;
}
}
else
printf("%lld\n",ans);
}
return 0;
}
H - 本题主要考察了DFS
题目链接:本题主要考察了DFS
算法标签:【枚举】
思路:对于一个拼图来说,总共凸起和凹下的数量相同。因此可以遍历计算出最后一片拼图是否有凸起和凹下,也可以都存在。最后需要求的是制作成本,凹下的成本-1,凸起成本+1,原成本为10。
代码:
#include <iostream>
using namespace std;
void solve()
{
int n;
cin >> n;
string str;
int cnt = 0; // cnt碰到凹下+1,碰到凸起-1
for(int i = 1;i <= n*n-1;i ++)
{
cin >> str;
for(int j = 0;j < 4;j ++)
{
if(str[j] == '1')
cnt ++;
else if(str[j] == '2')
cnt --;
}
}
printf("%d\n",10 + cnt);
}
int main()
{
int T;
cin >> T;
while(T --)
solve();
return 0;
}
I - 本题也主要考察了DFS
题目链接:本题也主要考察了DFS
留坑
J - 本题竟也主要考察了DFS
题目链接:本题竟也主要考察了DFS
留坑
K - 本题主要考察了dp
题目链接: 本题主要考察了dp
算法标签:【构造】【枚举】
思路:根据题意和样例,构造出坏区间总数最少的字符串,在1的个数和0的个数够用的情况下,两个1中间包含两个0,1001
;当1或0的个数不够时,字符串的剩下位置全放1或0。构造出字符串后,遍历找出坏区间的数。
代码:
#include <iostream>
using namespace std;
int main()
{
int n , cnt1 , cnt0;//cnt1为1的个数,cnt0为0的个数
cin >> n >> cnt1;
cnt0 = n - cnt1;
string str = "?";
for(int i = 1;i <= n;i ++)
{
if(cnt1) // 如果1的个数还有的话,字符串末尾加1
{
str += '1';
cnt1 --;
}
if(cnt0)// 如果0的个数还有的话,字符串末尾加0
{
str += '0';
cnt0 --;
if(cnt0) // 为了构造坏区间最少的字符串,两个1中间包含两个0,即1001,判断是否能放第二个0
{
str += '0';
cnt0 --;
i ++;
}
}
}
int ans = 0;
//计算坏区间的数量
for(int i = 1;i <= n - 2;i ++)
{
int l = i,r = i + 2;
int cnt = 0;
for(int j = l;j <= r;j ++)
cnt += str[j] - '0';
if(cnt > 1)
ans ++;
}
printf("%d\n",ans);
return 0;
}
L - 本题主要考察了运气
题目链接:本题主要考察了运气
算法标签:【数论(概率论)】
思路:@eyuhaobanga:
问团队和问个人是独立的:
- 问团队:问一次、问两次、问三次、问四次、问四次
期望:(1+2+3+4+4)/5 = 2.8 - 问个人:问一次、问两次、问三次、问三次
期望:(1+2+3+3)/4 = 2.25
2.8+2.28=4.05 选项:32
代码:
#include <iostream>
using namespace std;
int main()
{
printf("32\n");
return 0;
}
m - 本题主要考察了找规律
题目链接: 本题主要考察了找规律
算法标签:【动态规划】
思路:dp[i][j]
表示已经给i
个人分了j
仙贝,所收获的最大好感度。
- 转移方程:
枚举第i个人分到的仙贝数k
答案就是:dp数组的最大值。
代码:
#include <iostream>
using namespace std;
int n ,m;
double dp[510][510];
int main()
{
cin >> n >> m;
for(int i = 1;i <= n;i ++)
for(int j = 0;j <= m;j ++)
for(int k = 0;k <= j;k ++)
dp[i][j] = max(dp[i][j] ,dp[i-1][j-k]+k*1.0/(m-(j-k)) );
double ans = 0;
for(int i = 1;i <= n;i ++)
for(int j = 0;j <= m;j ++)
ans = max(ans , dp[i][j]);
printf("%.9lf",ans);
return 0;
}