目录
2021/5/31 21:15
Problem A. 玄武国
Input file : standard input
Output file: standard output
Time limit: 1 second
Memory limit: 256 megabytes
小 E 只身来到玄武国,准备在一排只有 n 个客栈的地方住宿,这个街道有m 名刺客组织的刺客,每个刺客的监测半径范围是 k。也就是说,对于处于在 f号客栈的刺客,他可以监测到[f-k,f+k]所有的客栈。小 E 不想过多的与刺客组织接触,他已经知道了每个刺客所在的客栈以及监测半径。小 E 想知道每个客栈被多少个刺客所监测。
Input:
第一行包含两个正整数 n 和 m,之间使用一个空格符分隔,分别为客栈的数目以及刺客的数量。
第二行开始连续 m 行,每行包含两个整数,相邻整数之间使用一个空格符分隔,分别是刺客所在的客栈 f 和监测半径 k。
数据规范:
1<=n<= 1<=m<=
1<=f<=n 0<=k<=
Output:
输出一行,包含 n 个整数,相邻整数之间使用一个空格符分隔,输出的第 i 个整数表示编号为 i 的客栈正在被监测的刺客数量 。
Example:
输入
5 3
1 0
3 2
2 2
输出
3 2 2 2 1
思路:
本题属于是区间修改,查询只针对最后一次的查询,注意到数据范围是,所以不能用双重for循环,不能暴力,所以用差分处理出每次修改的端点处的信息,最后查询时用一个前缀和遍历一遍即可得到每个刺客的检测的数量。
知识点:
差分+前缀和
感想:
本题针对新手有难度,但接触过一点算法来说还是可以是个签到题,这种题在cf上可以说是常做题型了,但校赛时还是wa了一发,好像记得时数组越界问题,哎,还是基础啊......
#include<bits/stdc++.h>
using namespace std;
int x[1000005]={0},m,n;
int main(){
cin>>n>>m;
for(int i=0;i<m;i++){
int f,k;
cin>>f>>k;
if(f-k<=1)x[1]++; //注意数组越界情况
else x[f-k]++;
if(f+k+1>n)x[n+1]--;
else x[f+k+1]--;
}
for(int i=1;i<=n;i++){
x[i]=x[i-1]+x[i];
cout<<x[i]<<" ";
}
cout<<endl;
return 0;
}
2021/6/1 21:25
Problem B. 星星月亮太阳皇冠
Input file : standard input
Output file: standard output
Time limit: 1 second
Memory limit: 256 megabytes
用户的 QQ 等级由四个标识图展示,从低到高分别为星星、月亮、太阳、皇冠。其中,4 星星=1 月亮,4 月亮=1 太阳,4 太阳=1 皇冠。 假设用户的等级为 N,则等级换算成活跃天数 D 为:D=N^2+4×N现给出由皇冠(Crown),太阳(Sun),月亮(Moon),星星(Star)组成的字符串,输出用户 QQ 等级和需要活跃天数
Input:
第一行输入一个 t,表示 t 组数据(t<=50)。
接下来 t 行每行输入一个字符串 s,表示用户等级图标。
1<=|s|<=100
数据保证符合 QQ 等级规则
Output:
输出两个整数,分别表示用户等级和此等级需要的活跃天数,中间用一个空格隔开。
Example:
输入
3
Star Star Star
Crown Sun Moon Star
Sun Sun Moon Moon
输出
3 21
85 7565
40 1760
思路:
对于输入的字符串进行处理,判断出其中出现的 Star Moon Sun Crown出现的次数,通过公式计算得出答案。
知识点:
对于字符串的基本处理
感想:
本题属于真正的签到题,不需要算法基础,但考察语言的基础,记得当时试了好几遍,还是对空格回车的字符处理方式不熟练,并且getline用的不熟悉。
#include<bits/stdc++.h>
using namespace std;
int ans=0;
void solve(string s){
if(s=="Star")ans+=1;
else if(s=="Moon")ans+=4;
else if(s=="Sun")ans+=16;
else if(s=="Crown")ans+=64;
}
int main(){
int t;
cin>>t;
getchar(); //后面要用getline先处理掉前面残留的回车
while(t--){
string s,s1;
ans=0;
getline(cin,s);
int len=s.size();
s[len]=' '; //对最后的也加上一个空格方便处理
s[len+1]='\0'; //字符串结束标志别忘了
for(int i=0;i<len+1;i++){
if(s[i]!=' '){
s1+=s[i];
}if(s[i]==' '){
solve(s1);
s1.clear(); //每轮都要清空s1
}
}cout<<ans<<" "<<ans*ans+4*ans<<endl;
}
return 0;
}
2021/8/18 15:31
Problem C. 世界线变动
Input file : standard input
Output file: standard output
Time limit: 1 second
Memory limit: 256 megabytes
小 I 刚刚获得了观测其他世界线的能力,他喜欢的一部漫画就烂尾了,小I 不甘心,他想去看看其他世界线的结尾。整个世界线成一颗树结构,树的根为世界线(漫画)的起源,1 号节点为根节点,每个节点的分支代表此节点衍生出的不同剧情,每个分支都有一个权值,代表衍生出下一个剧情的时间,树的叶子节点表示世界线(漫画)的结局。小 I 会首先选择 其他世界线结局(叶子节点) 与 他所在的世界线(叶子节点) 时间跨度最小的进行观测,小 I 认为,如果一个世界线结局衍生出来的时间小于 k ,此世界线结局是不好的,他不会去观测。求小 I 第一次观测其他世界线的结局编号。简单来说,小 I 是要从编号为m 的叶子节点访问与它 时间跨度最小 的一个叶子节点(此节点与根节点的时间跨度大于等于 k),如果有多个时间跨度最小的叶子节点,选择编号最小的那个。
Input:
第一行输入 n ,m 和 k ,n 是世界线节点的数量,小 I 最初在编号为 m 的节点。k 为小 I
观测世界线结局的最低衍生时间。
接下来的 n-1 行,每行一组 x,y,z,表示衍生出 x,y 节点之间用的时间 z。
数据规范:
2<=n,m<=10 5 保证 m 为叶子节点。
1<=k,z<=10 5 ;
1<=x,y<=n x!=y
Output:
输出结果为一行,包含一个整数,表示小 I 最先观测到的其他世界线结局的编号。如果没有观测到,输出"-1"。
Example:
输入
8 8 3
1 2 1
5 6 8
6 7 7
5 8 2
1 5 1
2 4 2
2 3 1
输出
4
说明:
图中红色表示的是衍生出每个节点的时间(边权),蓝色表示衍生出世界线结局(叶子节点)的时间。由图可知,离 8 号节点时间跨度最小的是 3 号节点。但是 3 号节点衍生时间<k,不符合小I 观测原则。故小 I 选择去观看 4 号节点的结局。为什么答案不是 8 号节点呢? 因为 8 号节点是小 I 本身的世界线结局,已经烂尾了,小 I 想去其他世界线看看。
思路:
题目中的最小事件跨度即为对于点m,其他叶子节点与其距离最小的点。
以根节点出发,通过dfs/bfs得到每个叶子节点到根节点的距离dis1。
以点m出发,通过dfs/bfs得到其他的叶子节点到点m的距离dis2。
对dis2升序排序,然后遍历一遍看是否符合题意即可。
知识点:
搜索,dfs/bfs,题意的理解
感想:
题目复杂,本质简单。
#include<bits/stdc++.h>
using namespace std;
const int mxn=1e5+7;
struct node{
int to;
long long value;
}dis2[mxn];
long long dis1[mxn];
vector<node> mp[mxn];
int vis[mxn];
int n,m,t,cnt;
bool cmp(node a,node b){
if(a.value==b.value)return a.to<b.to;
else return a.value<b.value;
}
void bfs(){
queue<node> q;
q.push(node{1,0}); //将根节点放入队列中
while(!q.empty()){
node k=q.front();
q.pop();
if(vis[k.to]==1)continue;
vis[k.to]=1; //标记
if(k.to!=1&&mp[k.to].size()==1){
dis1[k.to]=k.value; //记录根节点到叶子节点的距离
}else {
for(int i=0;i<mp[k.to].size();i++){
if(vis[mp[k.to][i].to]==0){
q.push(node{mp[k.to][i].to,mp[k.to][i].value+k.value});
} //将此节点能够往下走的所有节点入队
}
}
}
}
void bfs1(){
memset(vis,0,sizeof(vis));
queue<node> q;
q.push(node{m,0}); //将主角当前所在的点m加入队列
while(!q.empty()){
node k=q.front();
q.pop();
if(vis[k.to]==1)continue;
vis[k.to]=1;
if(k.to!=m&&k.to!=1&&mp[k.to].size()==1){ //不是初始点和根节点,即是其他的叶子节点那么将其相关数据保存
dis2[cnt].to=k.to;;
dis2[cnt].value=k.value;
cnt++;
}else {
for(int i=0;i<mp[k.to].size();i++){
if(vis[mp[k.to][i].to]==0){
q.push(node{mp[k.to][i].to,mp[k.to][i].value+k.value});
}
}
}
}
}
int main(){
scanf("%d%d%d",&n,&m,&t);
memset(dis2,0,sizeof(dis2));
for(int i=1;i<n;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
mp[x].push_back(node{y,z});
mp[y].push_back(node{x,z});
}bfs(); //得到每个叶子节点到根节点的距离
bfs1();
int flag=-1;
sort(dis2,dis2+cnt,cmp); //对叶子节点跟点m距离dis2优先根据距离排序,距离相同则根据标号排序
for(int i=0;i<cnt;i++){
if(dis2[i].to!=0&&dis2[i].value!=0){ //从dis2中挑出叶子节点满足题意并且此点与根节点的距离至少为t
if(dis1[dis2[i].to]>=t){
cout<<dis2[i].to<<"\n";
flag=i;
break;
}
}
}if(flag==-1)cout<<-1<<"\n";
}
2021/6/2 20:25
Problem D. 小天的问题
Input file : standard input
Output file: standard output
Time limit: 1 second
Memory limit: 256 megabytes
一天下午,小天和好朋友小梦一块出去玩。小天在墙壁上无意间发现了一串数字。爱动脑筋的小天想,这那么多数字里有多少个平方数?(平方数,是指可以写成某个整数的平方的数,即其平方根为整数的数。例如,9 = 3 × 3,9 是一个平方数。)你能帮帮小天解决这个问题吗?
Input:
第一行输入 t(t<=10), t 组输入数据;
每组数据的第一行是一个整数 n(n<=100),这一串数字的个数。
第二行是 n 个整数,A 1 ,A 2 ,A 3 ......A n (1<=A i <=10000)
Output:
输出每组中平方数的个数。
Example:
输入
3
1
1
5
1 2 3 4 5
3
4 16 233
输出
1
2
2
思路:
数据范围时候1-10000,所以预处理出1-100的平方,然后对于每个输入进行判断,也可以直接进行判断。
知识点:
平方数
感想:
这道题当时是队友做的,属于签到题
#include<bits/stdc++.h>
using namespace std;
int main(){
int t;
int x[101]={0};
for(int i=0;i<=100;i++){
x[i]=i*i; //预处理出1-100的平方数
}cin>>t;
while(t--){
int n;
cin>>n;
int ans=0;
for(int i=0;i<n;i++){
int a;
cin>>a;
for(int j=0;j<=sqrt(a);j++){
if(a==x[j]){
ans++;
break;
}
}
}cout<<ans<<endl;
}
return 0;
}
2021/6/5 16:55
Problem E. 想不出来背景
Input file : standard input
Output file: standard output
Time limit: 1 second
Memory limit: 256 megabytes
小 H,他,他想不出来背景了,题意如下。给定两个整数 a,b (a<=b)。令 c=a×(a+1)×(a+2)…(b-2)×(b-1)×b ;求 c 中所有质因子的和。结果可能很大,请输出对 +7 取模的结果。
Input:
输入为 1 行,包含两个整数 a,b。中间用一个空格符隔开。
2<=a<=b<=
Output:
在一行输出一个整数,表示答案。
Example:
输入
3 6
输出
17
说明
样例:
a=3,b=6
==>3×4×5×6
质因子和为: 3 + 2 + 2 +5 + 2 +3 = 17
思路:
质因子的和是为质数的因子和,首先看到数据范围可以确定需要用素数筛来处理处素数,并且C=a*...*b,所以我们需要在素数处理的时候处理出每个数的质因子的和,然后c的质因子的和即为每个相乘的数的质因子的和;
知识点:
素数筛(欧拉筛)
感想:
当时知道是用素数筛,但不知道如何处理出每个数的质因子的和,还是对素数筛的理解不全面,不彻底.....
#include<bits/stdc++.h>
using namespace std;
const int mxn=1e7+5,mod=1e9+7;
long long ans[mxn];
int p[mxn],vis[mxn];
int cnt=0;
void prime(){ //素数的处理
for(int i=2;i<=mxn-5;i++){
if(vis[i]==0){
vis[i]=1;
ans[i]=i; //每次遇到素数时,它对应的质因子的和即为它自己本身
p[++cnt]=i;
}for(int j=1;j<=cnt&&i*p[j]<=mxn-5;j++){
vis[i*p[j]]=1;
ans[i*p[j]]=(ans[i]+p[j])%mod; //对i这个数的质数倍的质因子的和为它自己加上所对应质数
if(i%p[j]==0)break;
}
}
}
int main(){
int a,b;
prime();
cin>>a>>b;
long long sum=0;
for(int i=a;i<=b;i++){
sum=(sum+ans[i])%mod; //对于C=a*...b求c的质因子和相当于是求a——b的各个数的质因子的和
}cout<<sum;
return 0;
}
2021/8/18 17:50
Problem F. 大大大灯泡
Input file : standard input
Output file: standard output
Time limit: 1 second
Memory limit: 256 megabytes
晚上有 n 个亮着的灯泡,标号从 1 到 n。 现在存在 2 种操作,如下:
操作 1,关掉标号 [l,r] 区间的灯
操作 2,打开标号 [l,r] 区间的灯
下面有 q 次询问,每次询问执行其中一种操作,询问格式 l,r,k。 k 为执行操作种类。对于每次询问回答当前开着的灯的数量。
Input:
单组输入,第一行包含一个整数 n,第二行一个整数 q(1≤n≤10 9 ,1≤q≤3·10 5 )
接下来 q 行每行 3 个整数表示询问 l,r,k(1 ≤ l ≤ r ≤ n, 1 ≤ k ≤ 2).
Output:
对于每次询问回答一个整数占一行表示答案。
Example:
输入
4
6
1 2 1
3 4 1
2 3 2
1 3 2
2 4 1
1 4 2
输出
2
0
2
3
1
4
思路:
区间多次操作,同时数据范围过大,因此,现需要对操作的端点进行离散化处理,然后对于区间的操作,线段树,每个节点维护一段区间的值,打懒标记。
知识点:
离散化+线段树区间操作
感想:
对于线段树的区间操作不熟悉,对于线段树的每个节点维护一段区间来说右端点+1的操作先前不懂,后来慢慢明白了。
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
const int maxn=3e5+5;
int k=1;
struct node{
int l;
int r;
int val;
int flag;
}T[maxn*32];
int n;
int cnt=0;
int lsh[maxn*8],num[maxn*8],f[8*maxn];
void LSH(int n){
sort(lsh+1,lsh+n+1); //对数组排序
int size = unique(lsh+1,lsh+n+1)-(lsh+1);
cnt=size;
for(int i=1;i<=n;i++){
num[i]=lower_bound(lsh+1,lsh+size+1,num[i])-lsh;
}
}
void BT(int L,int R,int rt){ //建树
if(L==R){ //叶子节点的l,r,即一次赋值为离散化前的值,表示维护这个区间的和
T[rt].l=lsh[k];
T[rt].r=lsh[++k];
T[rt].val=T[rt].r-T[rt].l;
return ;
}int mid=(L+R)/2;
BT(L,mid,rt*2);
BT(mid+1,R,rt*2+1);
T[rt].l=T[rt*2].l;
T[rt].r=T[rt*2+1].r;
T[rt].val=T[rt].r-T[rt].l;
}
void down(int rt){
if(T[rt].flag==1){
T[rt*2].val=T[rt*2+1].val=0;
}if(T[rt].flag==2){
T[rt*2].val=T[rt*2].r-T[rt*2].l;
T[rt*2+1].val=T[rt*2+1].r-T[rt*2+1].l;
}
if(T[rt].flag)T[rt*2].flag=T[rt*2+1].flag=T[rt].flag,T[rt].flag=0;
}
void update(int L,int R,int rt,int f){
if(T[rt].l>=lsh[R]||T[rt].r<=lsh[L])return ;
if(T[rt].l>=lsh[L]&&T[rt].r<=lsh[R]){
if(f==1)T[rt].val=0; //将区间和清0
if(f==2)T[rt].val=T[rt].r-T[rt].l; //区间和为左右端点值差因为右端点已经+1,左右不用+1操作了
T[rt].flag=f; //打上标记
return ;
}down(rt);
update(L,R,rt*2,f);
update(L,R,rt*2+1,f);
T[rt].val=T[rt*2+1].val+T[rt*2].val;
}
int main(){
scanf("%d",&n);
int q;
scanf("%d",&q);
lsh[0]=0;
int i;
for(i=1;i<=2*q;i+=2){
scanf("%d%d%d",&num[i],&num[i+1],&f[i]);
num[i+1]++; //右端点向右移一格,表示线段树操作的区间为左闭右开。
lsh[i]=num[i];
lsh[i+1]=num[i+1];
}
lsh[2*q+1]=1;lsh[2*(q+1)]=n+1; //将左右端点加入lsh中
LSH(2*(q+1)); //离散化
BT(1,cnt-1,1);
lsh[0]=0;
for(i=1;i<=2*q;i+=2){
update(num[i],num[i+1],1,f[i]);
cout<<T[1].val<<"\n";
}
return 0;
}
2021/6/3 21:20
Problem G. 玩游戏
Input file : standard input
Output file: standard output
Time limit: 1 second
Memory limit: 256 megabytes
Alice 和 Bob 正在玩 n 堆石头的游戏。保证 n 是偶数。第 i 堆有 ai 个石头。Alice 和 Bob 轮流玩一个回合,Alice 先手。在每个玩家的回合中,他们必须选择 n/2 个非空的堆,并从每一个被选择的堆中移除数量为正值的石头。他们可以在一个回合中移除不同数量的石头。第一个无法移动的玩家输了(当非空堆少于 n/2 时)。给定初始数据,决定谁将赢得比赛,输出赢得比赛的人。
Input:
第一行包含一个整数 n(2≤n≤50),即石头堆数。数据保证 n 是偶数。
第二行包含 n 个整数 a 1 ,a 2 ,…,a n (1≤a i ≤50)---每堆堆中的石头的数量。
Output:
如果 Alice 赢了,打印一个字符串“Alice”;否则,打印“Bob”(不带双引号)。
Example:
输入
4
3 1 4 1
输出
Alice
说明
在示例中,Alice 可以在第一次移动时从第一堆中移走 2 颗石子,从第三堆中移走 3 颗石
子,以确保它获胜。
输入
4
1 1 1 2
输出
Bob
说明
Alice 必须取 n/2=2 堆石子,不管怎么取,都会使一堆石子变为 0。Bob 将 n/2 堆取为
0 后,Alice 就没办法继续取了,Bob 胜
思路:
博弈题,A是先手,对样例分析可以得出如果一个人是其中一个石子变成0,那么这个人必输,推广一下,如果最小值的个数大于n/2,那么A第一轮必然会选到一个最小值,然后会使最小值变小,那么B选n/2后使之变成当前最小值,则再次轮到A时A又不得不选到一个最小的,直至最后A使最小值变成0,那么A输。
可以得出结论:当最小值的个数大于n/2时,A输B赢。当最小值个数等于n/2时,A赢B输。
当最小值个数小于n/2时,A赢B输。
知识点:
基础的博弈分析
感想:
校赛时,我们三个都没学博弈,然后被这个题上疯狂折磨,最后也没过,后来想想,当时只是分析到最后将1-0的情况,而没有推广到基本的情况,博弈差,感觉能做出来,但又做不出来的题真是折磨。(加强学习博弈)。
#include<bits/stdc++.h>
using namespace std;
int x[101];
int main(){
int n;
cin>>n;
for(int i=0;i<n;i++){
int a;
cin>>a;
x[a]++;
}int max=0;
for(int i=1;i<101;i++){
if(x[i]!=0){
max=x[i]; //找出最小数的出现次数。
break;
}
}if(max<=n/2)cout<<"Alice"<<endl;
else cout<<"Bob"<<endl;
return 0;
}
Problem H. 我的回合抽卡
Input file : standard input
Output file: standard output
Time limit: 1 second
Memory limit: 256 megabytes
“我的回合 抽卡” --室友最近沉迷于卡牌游戏给出一套数量为 n 的卡组,从 1 开始编号,每张卡都有一个固有属性--战力。然后给出 m 组羁绊(x,y,z),表示同时挑选第 x 张卡和第 y 张卡时会额外增加战力 z ,同时不选会额外减少战力 z 。
求在卡组中挑选出卡牌的最大战力和。
Input:
第一行两个整数 n ,m 表示卡牌的数量和 m 组羁绊
第二行 n 个整数,a[i]表示每张卡的战力
随后 m 行,每行三个整数(x,y,z),表示一组羁绊
数据规范:
n,m<=100000
|a[i]|<=10000
1<=x,y<=n x!=y
0<=z<=10000
Output:
一个整数,表示最大战力和。
Example:
输入
2 1
-10 -10
1 2 5
输出
-5
说明
一个都不选
思路:
对于每组的羁绊,相当于是同时选x,y则会增加战力z,同时不选会减少战力z。
那么我们可以每次让ans先减去z然后在让x,y牌战力分别加z,则同时选会时总战力额外加z,同时不选会使总战力额外减z,选一张牌则总战力额外不会加减。
知识点:
思维
感想:
思维题目,但几乎没人做...
#include<bits/stdc++.h>
using namespace std;
int main(){
long long n,m;
cin>>n>>m;
long long a[100005]={0};
for(int i=1;i<=n;i++)cin>>a[i];
long long ans=0;
for(int i=0;i<m;i++){
long long x,y,z;
cin>>x>>y>>z;
ans-=z;
a[x]+=z;
a[y]+=z;
}for(int i=1;i<=n;i++){
if(a[i]>=0)ans+=a[i]; //只要i对应的战力不小于0,那么就可选上
}
cout<<ans<<"\n";
return 0;
}
2021/6/4 21:00
Problem I. 未雨绸缪
Input file : standard input
Output file: standard output
Time limit: 1 second
Memory limit: 256 megabytes
小 C 是一个水果商人,他有 n 个袋子,下标从 1 到 n ,下标为 i 的袋子里有 i 个水果。一个顾客提前预约了小 C 买数量范围为[1,n]的水果,但小 C不知道他具体买多少个水果。小 C 需要从这 n 个袋子里选出 k 个袋子(对于每个下标为 i 的袋子只能选一次),使得顾客购买任何一个数量的水果小 C 都能满足顾客需求。这 k 个袋子里的水果可以相互转移,每次转移必须是一个袋子里的水果全部转移到另一个袋子中。求小 C 需要选出袋子个数 k 的最小值。
Input:
第一行输入一个 t(1<=t<=10 5 )。表示测试数据个数
随后 t 行,每行一个整数 n。n 是小 C 拥有的袋子数量和顾客的最大需求。
1<=n<=10 9
Output:
对于每个测试数据,输出一个整数表示答案。
Example:
输入
3
1
3
6
输出
1
2
3
说明:
对于第三个测试用例 6
我们可以选择 1 2 3
1: 1
2: 2
3: 3
4: 1+3
5: 2+3
6: 1+2+3
选择 3 个整数即可
当然,我们也可以选择 1 2 4
思路:
可以通过慢慢推来发现规律。
1——1;
2——1+2;
3——1+2;
4——1+2+3;
5——1+2+4;
6——1+2+4;
7——1+2+4;
8——1+2+4+5;
9——1+2+4+5;
15——1+2+4+8;
·
·
·
可以发现当到4的时候原来的1,2最大能表示的就是3;所以当第三个是3的时候可以增加到4;第四个数同理1+2+4,可以代替到7,后来就需要出现8;可以得到结论就是选出的最小袋子为1,2,4,8,16...为能表示出的最小的n;
思路2(似乎是正解):
推理差不多,后来的1,2,4,8...将其转化为2进制表示为:
1: 1;
2: 10;
4: 100;
可以得出结论为我们需要算出n是2的多少次幂就可以。
知识点:
思维题,推理。
感想:
当时在赛场上这道题也卡了我们好久,刚开始一直在错误的思路里往下推,一直推不出来,到最后才真正的想到了表示的问题,自己有很多方面的问题。
题意还没完全理解透彻就开始上手做题,导致更加的浪费时间,思路局限,思维感觉还是不行。
#include<bits/stdc++.h>
using namespace std;
int main(){
int t;
cin>>t;
while(t--){
int n;
int flag=0;
cin>>n;
for(int i=0;i<30;i++){ //先算出来1e9的最大范围
if(pow(2,i)>n){
flag=i;break;
}
}cout<<flag<<endl;
}
}
// 或者直接循环/2
#include<bits/stdc++.h>
using namespace std;
int main(){
int t;
cin>>t;
while(t--){
int n;
int ans=0;
cin>>n;
while(n){
n/=2;
ans++;
}cout<<ans<<endl;
}
}
2021/6/7 20:10
Problem J. vivy
Input file : standard input
Output file: standard output
Time limit: 1 second
Memory limit: 256 megabytes
vivy 是一台自律人形 Ai,为了达成自己被赋予的“透过歌唱让大家幸福”这一使命,vivy 不论何时都全心歌唱,她的目标是站到主舞台之上。现在给出 n 首歌曲的受欢迎程度 a 1 ,a 2 ,a 3 … a n 。现在 vivy 需要选出 k 组歌曲:[l 1 ,r 1 ],[l 2 ,r 2 ] … [l k ,r k ] (1<=l 1 <=r 1 <l 2 <=r 2 … <l k <=r k <=n; r i -l i +1=m);使得选出的 k 组歌曲受欢迎程度之和是所有可能里最大的。
Input:
第一行输入 3 个整数 n,m,k。分别表示歌曲的数量 n,每组歌曲的数量 m,需要选 k 组歌曲。中间用空格隔开。
第二行 n 个整数,a 1 ,a 2 · · · a n 。表示每个歌曲的受欢迎程度。
数据规范:
1<=(m×k)<=n<=5000。
0<=a i <=
Output:
输出一个整数,表示最大的受欢迎程度和。
Example:
输入
5 2 1
1 2 3 4 5
输出
9
思路:
看到数据范围与题意的选出最优解,可以大概试一下能不能用dp来做,定义状态dp[i][j]为前i有个去中选j个组的最大欢迎程度,那么对于第i首歌曲,我们可以选,也可以不选。
1、当我们选第i首歌曲时,由于要满足题目中的l与r的关系,所以dp[i][j]=dp[i-m][j-1]+(这以i为结尾的m首歌曲的受欢迎程度之和),由于我们需要多次的连续区间求和,可以用前缀和相减来加速,即dp[i][j]=dp[i-m][j-1]+sum[i]-sum[i-m];
2、当我们不选第i首歌曲时,dp[i][j]=dp[i-1][j];
因此我们得到状态转移方程:dp[i][j]=max(dp[i-1][j],dp[i-m][j-1]+sum[i]-sum[i-m]);
初始状态的确定,我们的i要从m开始。
知识点:
dp,前缀和连续区间求和
感想:
dp还是不会,每次的dp问题定义不出来,如何做....
#include<bits/stdc++.h>
using namespace std;
long long dp[6000][6000],sum[6000];
int main(){
int n,m,k;
cin>>n>>m>>k;
for(int i=1;i<=n;i++){
int a;
cin>>a;
sum[i]=sum[i-1]+a;
}
for(int i=m;i<=n;i++){
for(int j=1;j<=k;j++){
dp[i][j]=max(dp[i-1][j],dp[i-m][j-1]+sum[i]-sum[i-m]);
}
}cout<<dp[n][k]<<endl;
return 0;
}
2021/6/5 17:07
Problem K. n皇后
Input file : standard input
Output file: standard output
Time limit: 1 second
Memory limit: 256 megabytes
有一个 n*n 的棋盘,棋盘上的一个格子可以放置一个皇后,每个皇后的攻击距离是它 所在的行 和 所在的列,为使皇后不能相互攻击,一个皇后的攻击距离内不能放置其他皇后,即:在(i,j)放置一个皇后,那么 i 行和 j 列的格子就不能再次放置其它皇后。显然,皇后最大放置数量为 n。求棋盘中放置这 n 个皇后的不同方案数。答案数值可能较大,请输出答案对 取模的结果。
只要两个方案不完全重叠,就认为两个方案不同。
Input:
第一行输入一个 t(1<=t<=1000)。表示测试数据个数
随后 t 行,每行一个整数 n。
1<=n<=100000
Output:
对于每个测试数据,输出一行, 放置这 n 个皇后的不同方案数。
Example:
输入
3
1
3
2333
输出
1
6
205311752
思路:
签到题,通过题意分析,可以得出每行每列只能放一个皇后,那么第一行有n种情况,第二行有(n-1)种情况......每种情况相互独立,故是相乘的情况。
知识点:
读题,分析,阶乘
感想:
简单签到.....
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int main(){
int t;
cin>>t;
while(t--){
int n;
cin>>n;
long long ans=1;
for(int i=1;i<=n;i++){
ans=ans*i%mod;
}cout<<ans<<endl;
}
}