724A - Checking the Calendar
#include<stdio.h> #include<string> #include<iostream> using namespace std; string s1,s2; int hs(string s) { if(s=="monday") return 1; else if(s=="tuesday") return 2; else if(s=="wednesday") return 3; else if(s=="thursday") return 4; else if(s=="friday") return 5; else if(s=="saturday") return 6; else if(s=="sunday") return 7; } int main() { cin>>s1>>s2; int a1=hs(s1),a2=hs(s2),pd=0; if(a1==a2||(a2-a1+7)%7==3||(a2-a1+7)%7==2) pd=1; if(pd) printf("YES"); else printf("NO"); return 0; }
724B - Batch Sort
#include<stdio.h> #include<algorithm> using namespace std; int x[21][21],yg[21],sf[21][21],bt[21]; int n,m; bool bzmd() { for(int i=1;i<=n;i++) { int s=0; for(int j=1;j<=m;j++) { s+=x[i][j]!=yg[j]; if(s>2) return 0; } } return 1; } int main() { int pd=1; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&x[i][j]),bt[i]+=x[i][j]!=j; for(int i=1;i<=m;i++) for(int i=1;i<=n;i++) if(bt[i]>4) { printf("NO"); return 0; } else if(bt[i]>2) pd=0; if(pd) { printf("YES"); return 0; } for(int i=1;i<=m;i++) yg[i]=i; for(int i=1;i<m;i++) for(int j=i+1;j<=m;j++) { swap(yg[i],yg[j]); if(bzmd()) { printf("YES"); return 0; } swap(yg[i],yg[j]); } printf("NO"); return 0; }
724C - Ray Tracing
题目大意:
在一个nXm的平面里,光线从(0,0)以45度角出发,遇到边界则发生反射,遇到角时就停止。
在平面中有些监视器坐标为(xi,yi),问你光线第一次经过监视器的时间(光线每秒走根号2单位长度)
解题思路:
思考在物理中学习平面镜是虚像的问题
我们可以通过做对称保持光线一直在走直线
纵向将所有点关于x=k*n(k=1,2,3,....)做对称,
横向将所有点关于y=k*m(k=1,2,3,...)做对称。
然后我们思考监视器的横向坐标为k*n+xi或者k*n-xi
纵向为k*m+yi或者k*m-yi
由于光线45度出发
所以与光线经过的一定是横纵坐标相等的点
也就是说横纵坐标相等
k1*n±xi=k2*m±yi
k1*n-k2*m=±(xi±yi)
此时就变成了一个关于k1,k2的不定方程组
就可以用exgcd求出一组解kk1,kk2
我们就可以得到通解为
k1=kk1-m/gcd(n,-m)*t;
k2=kk2-n/gcd(n,-m)*t;
t为整数
(这个不知道的还是去看看百科吧)
求出k1可能的最小正
之后只要再算出最小的正整数x,求出时间即可
至于xi,yi前面的正负,就把每种情况都算一遍。
#include<cstdio> #include<algorithm> typedef int int_; #define int long long using namespace std; int n,m,jt,x,y; int rd(){ char c; while((c=getchar())<'0'||c>'9') ; int re=c-'0'; while((c=getchar())>='0'&&c<='9') re=(re<<1)+(re<<3)+c-'0'; return re; } int mi(int a,int b){ return a>b?b:a; } int gcd(int a,int b){ return b?gcd(b,a%b):a; } void exgcd(int a,int b){ if(!b) x=1,y=0; else{ exgcd(b,a%b); int tx=y,ty=x-a/b*y; x=tx,y=ty; } } int js(int a,int b){ int c=b-a; if(c&1) return jt; c>>=1; int t=gcd(n,-m); if(c%t) return jt; exgcd(n,-m); x*=c/t;t=abs(m/t); x=(x%t+t)%t; int ti=2*n*x+a; if(ti<0||ti>jt) return jt; return ti; } int_ main(){ n=rd(),m=rd(); int k=rd(); jt=n*m/gcd(m,n); while(k--){ int a,b,ans=jt; scanf("%I64d%I64d",&a,&b); ans=mi(ans,js(a,b)); ans=mi(ans,js(-a,b)); ans=mi(ans,js(a,-b)); ans=mi(ans,js(-a,-b)); if(ans==jt) printf("-1\n"); else printf("%I64d\n",ans); } return 0; }
724D - Dense Subsequence
题目大意
给你一个序列s和一个整数m
对于每个s[i]可以选择或者不选
要求每个长度为m的子串中必须有一个元素是被选择的
问你所有选择的方式中
选择的所有s[i]排序后字典序最小的方式是哪个
要求输出最后排序的字符串
解题思路
首先我们思考
aab没有aaab优
aaab比aaabb优
什么意思呢?
假设这次我们所要选择的字符串至少为b
那么所有a都选上才更优
并且选的b越少越优
所以我们首先贪心求出最少要加入那些字符(尽量使用小字符的前提下),并且记录加入的最大字符
然后把所有比它小的字符都加入最后的字符串再排序就可以了
贪心的过程其实就是看目前还没有被覆盖的最靠左的长度为m的子串中的最小字符(同样小就要尽量靠右)是哪个,然后在到下个未覆盖的开始找
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=1e5+5; char s[N],a[N]; bool vis[N]; int to[30]; int main(){ int m,n,l=1,l1=0,mx=0; scanf("%d%s",&m,s+1); n=strlen(s+1); while(l+m-1<=n){ int mi=l; for(int i=l+1;i<=l+m-1;++i) if(s[i]<=s[mi]) mi=i; a[l1++]=s[mi]; l=mi+1; vis[mi]=1; if(s[mi]>mx) mx=s[mi]; } for(int i=1;i<=n;++i) if(s[i]<mx&&!vis[i]) a[l1++]=s[i]; sort(a,a+l1); printf("%s",a); return 0; }