标签:赋值 输出 def close 三角形 取值 isp info image
题意:
给出n,要求找到3个正整数x,y,z,使得x|n,y|n,z|n,x+y+z=n,并且x*y*z的值最大。
分析:
设x=n/r,y=n/s,z=n/t,且r<=s<=t,则1/r+1/s+1/t=1 => 3*1/r >=1,即r<=3。
当r=2时,1/s+1/t=1/2 => 2*1/s >=1/2,即s<=4,在根据s的取值确定t值。
同理,可以解出答案大概为(n/3,n/3,1/3),(n/4,n/4,n/2),(n/2,n/3,n/6)。
再看如果一个数能被2,3,6整除,那么它也可以被2,4,4整除,但是2*3*6>2*4*4,所以排除第三种情况。
代码:
#include <map> #include <queue> #include <vector> #include <math.h> #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; #define ull unsigned long long #define cls(x) memset(x,0,sizeof(x)) #define clslow(x) memset(x,-1,sizeof(x)) const int maxn=1e6+100; const int inf=0x3f3f3f3f; int n,T; int main() { // freopen("in.txt","r",stdin); scanf("%d",&T); while(T--) { ll ans=1; scanf("%d",&n); if(n%3==0){ ans=ans*(n/3)*(n/3)*(n/3); } else if(n%4==0){ ans=ans*(n/4)*(n/4)*(n/2); } else{ ans=-1; } printf("%lld\n",ans); } return 0; }
题意:
把n个字符串任意拼接后,求最长平衡子串(不一定连续)。定义平衡子串为连续的一段子串且左右括号匹配。是不是看上去有点绕,对于第一个样例)()(()(,它的平衡子串为【1,2】和【4,5】,这里【1,2】或者【4,5】的子串是连续的并且左右括号匹配,但是对于这两个子串来说他们是不连续的。
分析:
既然可以不用连续,我们首先把匹配的子串分离出来,然后每个字符串就变成了a个右括号和b个左括号,然后问题就变成了该怎么拼接这n个字符串。具体排序规则在代码中有解释。
参考资料:大佬博客
#include <set> #include <queue> #include <vector> #include <math.h> #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; #define ll long long #define ull unsigned long long #define cls(x) memset(x,0,sizeof(x)) #define clslow(x) memset(x,-1,sizeof(x)) #define FI(n) FastIO::read(n) const int maxn=1e5+100; int n,q,T; char s[maxn]; struct Node { ll l,r; bool operator < (const Node& rhs) const { //左少右多 vs 左多右少 if(l<=r&&rhs.l>=rhs.r) return false; //左多右少 vs 左少右多 else if(l>=r&&rhs.l<=rhs.r) return true; //左多右少 vs 左多右少 else if(l>=r&&rhs.l>=rhs.r) return r<rhs.r; //左少右多 vs 左少右多 else if(l<=r&&rhs.l<=rhs.r) return l>rhs.l; } }; Node node[maxn]; void solve(ll& l,ll& r,ll& ans) { int len=strlen(s); for(int i=0;i<len;i++){ if(s[i]==‘(‘) l++; else{ if(l>0) l--,ans+=2; else r++; } } } int main() { // freopen("in.txt","r",stdin); scanf("%d",&T); while(T--) { ll ans=0; scanf("%d%d",&n); for(int i=1;i<=n;i++){ scanf("%s",s); node[i].l=node[i].r=0; solve(node[i].l,node[i].r,ans); } sort(node+1,node+n+1); ll L=node[1].l,R=node[1].r; for(int i=2;i<=n;i++){ if(L<=node[i].r){ ans+=L*2; R+=node[i].r-L; L=node[i].l; } else{ ans+=node[i].r*2; L+=node[i].l-node[i].r; } } printf("%lld\n",ans); } return 0; }
题意:
给出3*n个点,3个点组成一个三角形,并且所有三角形之间不相交。
分析:
按照坐标的x,y坐标排序后,从小到大挑选。官方题解是用了凸包,赤裸裸的水过~~~
代码:
#include <map> #include <queue> #include <vector> #include <math.h> #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; #define ull unsigned long long #define cls(x) memset(x,0,sizeof(x)) #define clslow(x) memset(x,-1,sizeof(x)) const int maxn=1e6+100; const int inf=0x3f3f3f3f; int n,T; struct Point { int x,y,id; }; Point p[maxn]; bool cmp(Point a,Point b) { if(a.x==b.x) return a.y<b.y; return a.x<b.x; } int main() { // freopen("in.txt","r",stdin); scanf("%d",&T); while(T--) { scanf("%d",&n); n=n*3; for(int i=1;i<=n;i++){ p[i].id=i; scanf("%d%d",&p[i].x,&p[i].y); } sort(p+1,p+n+1,cmp); for(int i=1;i<=n;i+=3){ for(int j=i;j<i+3;j++){ if(j>i) printf(" "); printf("%d",p[j].id); } printf("\n"); } } return 0; }
题意:
给出数组的长度n,m个子区间,怎样赋值使得给出子区间内的每一个值都不相同,同时使得总数组的字典序最小。
分析:
先把子区间个按照l,r从小到大排个序。如果相邻的区间不想交,直接从1开始赋值就好了,如果有交集,用vis数组标记交集部分用了什么数,给该区间赋值时跳过这些值就好了。
代码:
#include <set> #include <queue> #include <vector> #include <math.h> #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; #define ll long long #define ull unsigned long long #define cls(x) memset(x,0,sizeof(x)) #define clslow(x) memset(x,-1,sizeof(x)) #define FI(n) FastIO::read(n) const int maxn=1e5+100; int n,q,T; int L,R,lastL,lastR; int a[maxn],vis[maxn]; struct Line { int l,r; bool operator < (const Line& rhs) const { if(l==rhs.l) return r<rhs.r; return l<rhs.l; } }; Line l[maxn]; //flag:true 从1开始赋值 false:全部赋值为1 void fillArray(int l,int r,int start,bool flag) { int val=start; for(int i=l;i<=r;i++){ a[i]=val; if(flag) val++; } } //处理交集部分 void solve(int pos,int pre) { L=l[pos].l,R=l[pos].r; lastL=l[pre].l,lastR=l[pre].r; //交集部分的数字标记为要赋值区间的id for(int i=L;i<=lastR;i++){ vis[a[i]]=pos; } int c=1; for(int i=lastR+1;i<=R;i++){ //如果c在该区间被赋值过,跳过 while(vis[c]==pos) c++; a[i]=c; vis[c]=pos; } } int main() { // freopen("in.txt","r",stdin); scanf("%d",&T); while(T--) { cls(vis); scanf("%d%d",&n,&q); for(int i=1;i<=q;i++){ scanf("%d%d",&l[i].l,&l[i].r); } sort(l+1,l+q+1); int la=1; for(int i=1;i<=q;i++){ L=l[i].l,R=l[i].r; lastL=l[la].l,lastR=l[la].r; //第一个子区间 if(i==1){ fillArray(1,L-1,1,false); fillArray(L,R,1,true); continue; } //如果有交集 if(L<=l[la].r){ //如果该区间包括在上一个区间内,跳过,因为一定是不同的 if(R<=l[la].r) continue; solve(i,la); } else{ fillArray(lastR+1,L-1,1,false); fillArray(L,R,1,true); } la=i; } //处理后面剩余的部分 fillArray(l[la].r+1,n,1,false); for(int i=1;i<=n;i++){ if(i>1) printf(" "); printf("%d",a[i]); } printf("\n"); } return 0; }
题意:
给出一个数组的通项公式,求前n项的和。
分析:
打表找规律题?大佬说什么就是什么吧……数组的值是没有什么规律的,但是数组的值出现的次数有规律,wtf。
好像看上去没什么规律,但是如果把第一项变为1,规律就出来了。
前2^n项的值为前2^(i-1)的值复制后,再把第2^i项+1,什么意思?好像还是有点难懂。
比如1,2 -> 1,3 1,2,1,3 -> 1,2,1,4 1,2,1,3,1,2,1,4 -> 1,2,1,3,1,2,1,5
然后通过打表找规律可以知道出现次数为i的数的首项为2^(i-1),公差为2^i(万恶的打表啊),所以我们就可以通过二分先求出第n个数的值,再通过等差数列求和得到前n个数的和。参考的大佬的博客,对代码加上了自己的理解。
参考资料:大佬博客
代码:
#include <set> #include <queue> #include <vector> #include <math.h> #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; #define ll long long #define ull unsigned long long #define cls(x) memset(x,0,sizeof(x)) #define clslow(x) memset(x,-1,sizeof(x)) const int mod=1e9+7; const int maxn=1e5+100; ll n,T,inv; //num:2^i区间共有多少数 //all:2^i区间所有数出现次数之和 ll num[maxn],all[maxn]; void init() { //2的逆元 inv=(mod+1)>>1; num[0]=1;all[0]=1; for(int i=1;i<=62;i++){ num[i]=num[i-1]*2; all[i]=all[i-1]*2+1; } } int main() { // freopen("in.txt","r",stdin); init(); scanf("%lld",&T); while(T--) { ll ans=0; scanf("%lld",&n); //计算出第n个数的值pos ll m=n,pos=0; for(int i=62;i>=0;i--){ if(m-all[i]>=0){ m-=all[i]; pos+=(1ll<<i); } } //如果pos出现的次数少于总共的次数 pos+=(m>0); //可能pos的值没有全部出现,所以放在后面计算 //cnt:总共计算了多少数的和 ll now=pos-1,cnt=0; //出现次数为i的数,首项为2^(i-1),公差为2^i for(int i=1;i<=62;i++){ if(num[i-1]>now) break; //首项 项数 末项 ll s=num[i-1],step=(now-s)/num[i]+1,e=s+(step-1)*num[i]; //出现次数为i的数的和 ll sum=(s+e)%mod*(step%mod)%mod*inv%mod; ans=(ans+sum*i%mod)%mod; //出现次数为i的数有step项 cnt+=step*i; } //把出现次数为pos的数的和加入答案 //因为把第一项2变为了1,所以答案需要+1,计算的项数之和需要减一 ans=(ans+1+(n-cnt-1)%mod*(pos%mod))%mod; printf("%lld\n",ans); } return 0; }
题意:
给出北京时间,输出所给时区的相对应的时间。
分析:
首先要知道怎么不同时区时间怎么转换,因为给定了UTC+X,所以该时区的时钟就是h+(X-8),分钟也对应这么处理一下,注意各种细节的处理就好了。
代码:
#include <map> #include <queue> #include <vector> #include <math.h> #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; #define ull unsigned long long #define cls(x) memset(x,0,sizeof(x)) #define clslow(x) memset(x,-1,sizeof(x)) const int maxn=1e6+100; const int inf=0x3f3f3f3f; int T,a,b,x,y; bool negative,flag; char s[10]; int main() { // freopen("in.txt","r",stdin); scanf("%d",&T); while(T--) { x=y=0; flag=false; scanf("%d%d%s",&a,&b,s); int len=strlen(s); if(s[3]==‘-‘) negative=true; else negative=false; for(int i=4;i<len;i++){ if(s[i]==‘.‘){ flag=true; continue; } if(flag) y=s[i]-‘0‘; else x=x*10+(s[i]-‘0‘); } if(negative) x=-x,y=-y; if(flag){ b=b+y*60/10; if(b>=60) a++,b=b%60; if(b<0) a--,b=(b+60)%60; } a=((a+x-8+24-1)%24+1)%24; printf("%02d:%02d\n",a,b); } return 0; }
2018 Multi-University Training Contest 1
标签:赋值 输出 def close 三角形 取值 isp info image
原文地址:https://www.cnblogs.com/shutdown113/p/9361672.html