Problem A
题意:给出一个串有n个字符,选择出k个字符,要求总和最小,且a[i]-a[i-1]>=2,存在就输出总和,不存在就输出-1。
思路:首先排序,然后一定是选取当前能取的最小的因为舍弃当前位置去取后面的首先当前不利,对于取下一位更小的也不利。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define for1(i,a,b) for (int i=(a);i<=(b);i++)
#define for0(i,a,b) for (int i=(a);i<(b);i++)
#define rof1(i,a,b) for (int i=(a);i>=(b);i--)
#define rof0(i,a,b) for (int i=(a);i>(b);i--)
#define pb push_back
#define fi first
#define se second
#define duozu int __T;scanf("%d",&__T);for1(ica,1,__T)
void _W(const int &x) { printf("%d", x); }
void _W(const ll &x) { printf("%I64d", x); }
void _W(const double &x) { printf("%.16f", x); }
void _W(const char &x) { putchar(x); }
void _W(const char *x) { printf("%s", x); }
void W(){}
template<class T, class... U> void W(const T &head, const U &... tail) { _W(head); putchar(sizeof...(tail) ? ' ' : '\n'); W(tail...); }
void _R(const int& x){ scanf("%d", &x); }
void _R(const ll& x){ scanf("%I64d", &x); }
void _R(const char* x){ scanf("%s", x); }
void R(){}
template<class T,class... U> void R(const T& head,const U& ...tail){_R(head);R(tail...);}
const int N = 50+5;
int a[N];
char s[N];
int main()
{
int n,k;
R(n,k);
scanf("%s",s);
for0(i,0,n) a[i] = s[i]-'a'+1;
sort(a,a+n);
//for1(i,0,n-1) W(a[i]);
int ans = 0;
int last = -100;
int cnt = 0;
for0(i,0,n){
if (a[i]-last>=2){
ans += a[i];
last = a[i];
cnt++;
}
if (cnt==k) break;
}
W(cnt==k?ans:-1);
return 0;
}
Problem B
题意:m个数字中取出n组数,每组内数字都相同,且个数为x,询问x的最大值。
思路:枚举x,判断是否可行,每种数我们都尽量多的利用。枚举x的过程可以二分。反正我当时傻没想到直接暴力枚举。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define for1(i,a,b) for (int i=(a);i<=(b);i++)
#define for0(i,a,b) for (int i=(a);i<(b);i++)
#define rof1(i,a,b) for (int i=(a);i>=(b);i--)
#define rof0(i,a,b) for (int i=(a);i>(b);i--)
#define pb push_back
#define fi first
#define se second
#define duozu int __T;scanf("%d",&__T);for1(ica,1,__T)
void _W(const int &x) { printf("%d", x); }
void _W(const ll &x) { printf("%I64d", x); }
void _W(const double &x) { printf("%.16f", x); }
void _W(const char &x) { putchar(x); }
void _W(const char *x) { printf("%s", x); }
void W(){}
template<class T, class... U> void W(const T &head, const U &... tail) { _W(head); putchar(sizeof...(tail) ? ' ' : '\n'); W(tail...); }
void _R(const int& x){ scanf("%d", &x); }
void _R(const ll& x){ scanf("%I64d", &x); }
void _R(const char* x){ scanf("%s", x); }
void R(){}
template<class T,class... U> void R(const T& head,const U& ...tail){_R(head);R(tail...);}
const int N = 1e5+5;
int a[110];
int main()
{
int n;
while (~scanf("%d",&n)){
memset(a,0,sizeof a);
int m;
R(m);
int x;
for1(i,1,m) scanf("%d",&x),a[x]++;
int ans = 100;
while (1){
int cnt = 0;
for1(i,1,100) cnt += a[i]/ans;
if (cnt>=n) break;
ans--;
if (ans==0) break;
}
W(ans);
}
return 0;
}
Problem C
题意:模拟火箭从星球起飞和降落到星球,起飞时每一单位油可以搭载ai单位的物品,落下时每一单位油可以搭载bi单位的物品,从一个星球到另一个星球的飞行图中不需要耗油。
给出行星数量n,给出飞行器本身重量,给出每一颗行星的ai,bi。
我们做的事情是从地球(1),飞到火星(n),再直接回到地球,询问最少需要多少单位的油。
思路:因为飞行器有重量>0,如果某个星球ai或者bi<=1,证明油连自己都飞起来都难带不上飞行器,此时输出-1。
排除上面情况后我们知道只要油多一定可以完成旅行。
油最少的话那么最后落回地球只剩飞行器重量,我们只需要一步步倒推。
地球上空到地球,接下来for(i=n;i>=2;i--) i号星球表面到天空,天空到表面
然后是地球表面到上空
总之正向过程逆推。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define for1(i,a,b) for (int i=(a);i<=(b);i++)
#define for0(i,a,b) for (int i=(a);i<(b);i++)
#define rof1(i,a,b) for (int i=(a);i>=(b);i--)
#define rof0(i,a,b) for (int i=(a);i>(b);i--)
#define pb push_back
#define fi first
#define se second
#define duozu int __T;scanf("%d",&__T);for1(ica,1,__T)
void _W(const int &x) { printf("%d", x); }
void _W(const ll &x) { printf("%I64d", x); }
void _W(const double &x) { printf("%.16f", x); }
void _W(const char &x) { putchar(x); }
void _W(const char *x) { printf("%s", x); }
void W(){}
template<class T, class... U> void W(const T &head, const U &... tail) { _W(head); putchar(sizeof...(tail) ? ' ' : '\n'); W(tail...); }
void _R(const int& x){ scanf("%d", &x); }
void _R(const ll& x){ scanf("%I64d", &x); }
void _R(const char* x){ scanf("%s", x); }
void R(){}
template<class T,class... U> void R(const T& head,const U& ...tail){_R(head);R(tail...);}
const int N = 1000+5;
int a[N],b[N];
int main()
{
int n;
while (~scanf("%d",&n)){
int pl;
bool flag = true;
R(pl);
for1(i,1,n) {R(a[i]);if(a[i]==1) flag = false;}
for1(i,1,n) {R(b[i]);if(b[i]==1) flag = false;}
if (flag == false){puts("-1");continue;}
double py = pl;
py += py/(b[1]-1);
rof1(i,n,2){
py += py/(a[i]-1);
py += py/(b[i]-1);
}
py += py/(a[1]-1);
printf("%.10f\n",py-pl);
}
return 0;
}
Problem D
题意:交互题,一个数x,范围1~m,然后你每次猜一个数,你会知道猜正确了还是偏大或者偏小,不幸的是告诉你每次询问结果的n台垃圾机器,第i台机器告诉你:你第i,i+n,i+2n...次询问的结果,那么他们为什么垃圾呢,因为有些机器会告诉你相反的答案而你不知道哪几台机器坏掉。
而你需要在这样一个条件下在60次内问出x。
思路:首先交互题大概是这样一个思路:这个回答提问的系统别人写好了,你想要获取信息,就读入东西,你想要发出询问,就输出东西给系统。
首先我们确定x<=m,那么我们先试出所有机器是否说真话,我们先问n次,每次问m就行,说你的答案偏小的机器百分之一百亿是在骗你,当然这个时候如果收到的回答是你答对了那么就直接结束了。
然后n<=30,最多用掉30次,接下去还剩30次,我们二分询问就可以解决
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define for1(i,a,b) for (int i=(a);i<=(b);i++)
#define for0(i,a,b) for (int i=(a);i<(b);i++)
#define rof1(i,a,b) for (int i=(a);i>=(b);i--)
#define rof0(i,a,b) for (int i=(a);i>(b);i--)
#define pb push_back
#define fi first
#define se second
#define duozu int __T;scanf("%d",&__T);for1(ica,1,__T)
void _W(const int &x) { printf("%d", x); }
void _W(const ll &x) { printf("%I64d", x); }
void _W(const double &x) { printf("%.16f", x); }
void _W(const char &x) { putchar(x); }
void _W(const char *x) { printf("%s", x); }
void W(){}
template<class T, class... U> void W(const T &head, const U &... tail) { _W(head); putchar(sizeof...(tail) ? ' ' : '\n'); W(tail...); }
void _R(const int& x){ scanf("%d", &x); }
void _R(const ll& x){ scanf("%I64d", &x); }
void _R(const char* x){ scanf("%s", x); }
void R(){}
template<class T,class... U> void R(const T& head,const U& ...tail){_R(head);R(tail...);}
const int N = 1000+5;
int n,m;
int p[40];
int a[40];
int main()
{
scanf("%d %d",&m,&n);
for1(i,1,n){
printf("%d\n",m);
fflush(stdout);
scanf("%d",&p[i]);
if (p[i]==0) return 0;
}
int l = 1,r = m;
for1(i,1,30){
int ans = l+r>>1;
printf("%d\n",ans);
fflush(stdout);
scanf("%d",&a[i]);
a[i] *= p[i%n==0?n:i%n];
if (a[i]==0) return 0;
else if (a[i]==1) r = ans-1;
else if (a[i]==-1)l = ans+1;
}
return 0;
}
Problem E
题意:给出n个数量不限的钞票面额,询问和在mod k的情况下余数有多少种。
思路:裴蜀定理:ax1 + bx2 + cx3 + dx4 .... = gcd(x1,x2,....xn) 一定有解(不会证,数论滚开)
推广: 左边 = m * gcd一定有解(m可以等于0,很显然,都为0就行了)
在本题中: 由于 mod k,所以 a<=>a+k<=>a+2k...所以所有系数可以加任意倍数k的整数倍结果一样,保证所有系数都为正。
因此所有可以形成的答案为m*gcd mod k,我们枚举m就行,从1枚举到k即可。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define for1(i,a,b) for (int i=(a);i<=(b);i++)
#define for0(i,a,b) for (int i=(a);i<(b);i++)
#define rof1(i,a,b) for (int i=(a);i>=(b);i--)
#define rof0(i,a,b) for (int i=(a);i>(b);i--)
#define pb push_back
#define fi first
#define se second
#define duozu int __T;scanf("%d",&__T);for1(ica,1,__T)
void _W(const int &x) { printf("%d", x); }
void _W(const ll &x) { printf("%I64d", x); }
void _W(const double &x) { printf("%.16f", x); }
void _W(const char &x) { putchar(x); }
void _W(const char *x) { printf("%s", x); }
void W(){}
template<class T, class... U> void W(const T &head, const U &... tail) { _W(head); putchar(sizeof...(tail) ? ' ' : '\n'); W(tail...); }
void _R(const int& x){ scanf("%d", &x); }
void _R(const ll& x){ scanf("%I64d", &x); }
void _R(const char* x){ scanf("%s", x); }
void R(){}
template<class T,class... U> void R(const T& head,const U& ...tail){_R(head);R(tail...);}
const ll mod = 1e9+7;
ll ft1(ll a,ll b){ll ans = 1;while (b){if (b&1) ans *= a;b>>=1,a*=a;}return ans;}
ll ft2(ll a,ll b){ll ans = 1;while (b){if (b&1) ans = ans*a%mod;b>>=1,a=a*a%mod;}return ans;}
const int N = 2e5+5;
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
int a[N];
int main()
{
int n,k;
while (~scanf("%d %d",&n,&k)){
for1(i,1,n) R(a[i]);
int g = n==1?a[1]:gcd(a[1],a[2]);
for1(i,3,n) g = gcd(g,a[i]);
for1(i,1,k){
a[i] = 1LL*i*g%k;
}
sort(a+1,a+1+k);
int cnt = unique(a+1,a+1+k)-a;
cnt--;
printf("%d\n",cnt);
for1(i,1,cnt){
if (i!=1) putchar(' ');
printf("%d",a[i]);
}puts("");
}
return 0;
}
Problem F
题意:给出一棵树,每个节点有一个指令,除了IN,都是自己的儿子进行某种运算,该节点的值等于儿子进行这种运算后的值,IN是从外部输入0或者1.
1是根节点,输出最后的结果。询问每个IN节点的值0变1,1变0后最终1节点输出啥(每次只假设其中一个节点变)
思路:dfs一遍,从底层到顶层处理出每个节点的值
然后接下去如何求出修改每一个点的后1输出的结果?我们还是dfs一遍,如果当前节点变化对结果有影响,那么我们尝试分别修改他的儿子看是否会对当前值产生影响,如果会,那么这个儿子的修改对最终结果有影响。(有影响就是指结果会从0变1,1变0)如果修改这个儿子当前节点值不变,那么这个儿子的一整棵子树修改都没有用啦,反正你不管怎么变我当前都没有影响。
所以再dfs一遍就可以,这次是从顶到底的过程。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define for1(i,a,b) for (int i=(a);i<=(b);i++)
#define for0(i,a,b) for (int i=(a);i<(b);i++)
#define rof1(i,a,b) for (int i=(a);i>=(b);i--)
#define rof0(i,a,b) for (int i=(a);i>(b);i--)
#define pb push_back
#define fi first
#define se second
#define duozu int __T;scanf("%d",&__T);for1(ica,1,__T)
void _W(const int &x) { printf("%d", x); }
void _W(const ll &x) { printf("%I64d", x); }
void _W(const double &x) { printf("%.16f", x); }
void _W(const char &x) { putchar(x); }
void _W(const char *x) { printf("%s", x); }
void W(){}
template<class T, class... U> void W(const T &head, const U &... tail) { _W(head); putchar(sizeof...(tail) ? ' ' : '\n'); W(tail...); }
void _R(const int& x){ scanf("%d", &x); }
void _R(const ll& x){ scanf("%I64d", &x); }
void _R(const char* x){ scanf("%s", x); }
void R(){}
template<class T,class... U> void R(const T& head,const U& ...tail){_R(head);R(tail...);}
const ll mod = 1e9+7;
ll ft1(ll a,ll b){ll ans = 1;while (b){if (b&1) ans *= a;b>>=1,a*=a;}return ans;}
ll ft2(ll a,ll b){ll ans = 1;while (b){if (b&1) ans = ans*a%mod;b>>=1,a=a*a%mod;}return ans;}
#define lson son[rt][0]
#define rson son[rt][1]
const int N = 1e6+5;
int son[N][2];
int op[N];
int v[N];
bool ans[N];
/*
1 IN
2 AND
3 XOR
4 NOT
5 OR
*/
int predfs(int rt){
if (op[rt]==1) return v[rt];
if (op[rt]==2) return v[rt] = predfs(lson)&predfs(rson);
if (op[rt]==3) return v[rt] = predfs(lson)^predfs(rson);
if (op[rt]==4) return v[rt] = predfs(lson)^1;
if (op[rt]==5) return v[rt] = predfs(lson)|predfs(rson);
}
void dfs(int rt,bool change01){
ans[rt] = change01;
if (!change01 || op[rt]==1) return ;
if (op[rt]==2){
if (((v[lson]^1)&v[rson])!=v[rt]) dfs(lson,true);
else dfs(lson,false);
if (((v[rson]^1)&v[lson])!=v[rt]) dfs(rson,true);
else dfs(rson,false);
}
if (op[rt]==3){
if (((v[lson]^1)^v[rson])!=v[rt]) dfs(lson,true);
else dfs(lson,false);
if (((v[rson]^1)^v[lson])!=v[rt]) dfs(rson,true);
else dfs(rson,false);
}
if (op[rt]==4){
dfs(lson,true);
}
if (op[rt]==5){
if (((v[lson]^1)|v[rson])!=v[rt]) dfs(lson,true);
else dfs(lson,false);
if (((v[rson]^1)|v[lson])!=v[rt]) dfs(rson,true);
else dfs(rson,false);
}
}
int main()
{
int n,x,y;
R(n);
char s[5];
for1(i,1,n){
R(s);
if (s[0]=='I') op[i] = 1;
if (s[0]=='A') op[i] = 2;
if (s[0]=='X') op[i] = 3;
if (s[0]=='N') op[i] = 4;
if (s[0]=='O') op[i] = 5;
if (op[i]==2 || op[i]==3 || op[i]==5) R(son[i][0],son[i][1]);
if (op[i]==4) R(son[i][0]);
if (op[i]==1) R(v[i]);
}
int rv = predfs(1);
dfs(1,true);
for1(i,1,n){
if (op[i]==1) printf("%d",ans[i]==true?rv^1:rv);
}puts("");
return 0;
}
确认过眼神,是全部补完的第一场。
我该怎么骗自己觉得写代码很有趣呢。。。