这次不是隔天,正好比赛是在8点开始,而且听说有车队,就打了一下,结果似乎不是那么的顺利。
A. Checking the Calendar
题意:题目给你两个星期,假如一个月的第一天是第一个星期,那么下个月的第一天有没有可能是第二个星期。月份只有可能是非闰年的月份。
分析:很简单的签到题,将给你的星期换成数字,分别为a和b(周日表示为0)。那么如果
a == b
或者
( a + 2 ) m o d 7 == b
或者
( a + 3 ) m o d 7 == b
中间有一个等式成立的话,就是YES(因为非闰年的月份只可能有28、30、31天)。
#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std ;
#define maxn 270000+10
#define SIZE 10000+5
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define clr(x,y) memset(x,y,sizeof(x))
#define rep(i,n) for(int i=0;i<(n);i++)
#define repf(i,a,b) for(int i=(a);i<=(b);i++)
#define pii pair<int,int>
#define mp make_pair
#define FI first
#define SE second
#define IT iterator
#define PB push_back
#define Times 10
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const double eps = 1e-14 ;
const double pi = acos (-1.0 );
const ll mod = 10007 ;
const int inf = 0x3f3f3f3f ;
const ll INF = (ll)1e18 +300 ;
const double delta = 0.98 ;
inline void RI(int & x)
{
x=0 ;
char c=getchar();
while (!((c>='0' &&c<='9' )||c=='-' ))c=getchar();
bool flag=1 ;
if (c=='-' )
{
flag=0 ;
}
while (c<='9' &&c>='0' )
{
x=x*10 +c-'0' ;
c=getchar();
}
if (!flag)x=-x;
}
char a[20 ],b[20 ];
int cal(char * str){
if (str[0 ]=='m' )return 1 ;
else if (str[0 ]=='t' ){
if (str[1 ]=='u' )return 2 ;
else return 4 ;
}
else if (str[0 ]=='w' )return 3 ;
else if (str[0 ]=='f' )return 5 ;
else if (str[1 ]=='a' )return 6 ;
else return 0 ;
}
int main(){
scanf ("%s" ,a);
scanf ("%s" ,b);
int aa=cal(a);
int bb=cal(b);
if (aa==bb||(aa+2 )%7 ==bb||(aa+3 )%7 ==bb)puts ("YES" );
else puts ("NO" );
return 0 ;
}
B. Batch Sort
题意:给出一个数字矩阵n*m,每一行是从1到m的所有数字的一个排序。问某个数字矩阵可不可以通过每行不超过一次的交换两个数的位置,和不超过一次的将两列整体交换。使得最后操作玩的数字矩阵每一行都是递增的
分析:看见数据范围很小,然后思考一下应该没有比暴力更好的方法了。每次先枚举一下交换的两列(n^2),当然也要考虑不交换的情况,特判一下。交换之后,对每一行扫描(n),如果位置(n)不对的地方有2个以上,那么不可以通过一次交换使得最后这一行是递增的。如果对于每一行都只有不超过2个的位置不同,那么这种交换就是成功的。最后的复杂度是o(n^4)
#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std ;
#define maxn 270000+10
#define SIZE 10000+5
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define clr(x,y) memset(x,y,sizeof(x))
#define rep(i,n) for(int i=0;i<(n);i++)
#define repf(i,a,b) for(int i=(a);i<=(b);i++)
#define pii pair<int,int>
#define mp make_pair
#define FI first
#define SE second
#define IT iterator
#define PB push_back
#define Times 10
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const double eps = 1e-14 ;
const double pi = acos (-1.0 );
const ll mod = 10007 ;
const int inf = 0x3f3f3f3f ;
const ll INF = (ll)1e18 +300 ;
const double delta = 0.98 ;
inline void RI(int & x)
{
x=0 ;
char c=getchar();
while (!((c>='0' &&c<='9' )||c=='-' ))c=getchar();
bool flag=1 ;
if (c=='-' )
{
flag=0 ;
}
while (c<='9' &&c>='0' )
{
x=x*10 +c-'0' ;
c=getchar();
}
if (!flag)x=-x;
}
int n,m;
int dat[22 ][22 ];
bool check(){
for (int i=0 ;i<n;i++){
int num=0 ;
for (int j=0 ;j<m;j++)
if (dat[i][j]!=j+1 )
num++;
if (num>2 )return false ;
}
puts ("YES" );
return true ;
}
int main(){
scanf ("%d %d" ,&n,&m);
for (int i=0 ;i<n;i++)
for (int j=0 ;j<m;j++)
scanf ("%d" ,&dat[i][j]);
if (check())return 0 ;
for (int i=0 ;i<m;i++)
for (int j=i+1 ;j<m;j++){
for (int k=0 ;k<n;k++)
swap(dat[k][i],dat[k][j]);
if (check())return 0 ;
for (int k=0 ;k<n;k++)
swap(dat[k][i],dat[k][j]);
}
puts ("NO" );
return 0 ;
}
C. Ray Tracing
题意:在一个n*m的坐标图上给你k个点,从(0,0)向(1,1)射出一束镭射光线,镭射光线的速度是每秒
2 √
镭射光线碰到边界的时候满足物理定理进行反射(入射角等于出射角),当镭射光线射到四个角落的时候结束(不再反射)问每个点能不能被光线经过,不能经过输出-1,可以经过输出第一次经过的时间
分析:人家很快的推出公式了,因为是翻转不是平移,所以在系数上要乘以2。对于每个查询点(a,b),公式是
2 ∗ m ∗ x ± a = 2 ∗ n ∗ y ± b
,对于四种情况求出等号左边的最小整数解。妈蛋,本来有了公式是很好写的,但是就是各种小错误
#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std ;
#define maxn 270000+10
#define SIZE 10000+5
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define clr(x,y) memset(x,y,sizeof(x))
#define rep(i,n) for(int i=0;i<(n);i++)
#define repf(i,a,b) for(int i=(a);i<=(b);i++)
#define pii pair<int,int>
#define mp make_pair
#define FI first
#define SE second
#define IT iterator
#define PB push_back
#define Times 10
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const double eps = 1e-14 ;
const double pi = acos (-1.0 );
const ll mod = 10007 ;
const int inf = 0x3f3f3f3f ;
const ll INF = (ll)1e18 +300 ;
const double delta = 0.98 ;
inline void RI(int & x)
{
x=0 ;
char c=getchar();
while (!((c>='0' &&c<='9' )||c=='-' ))c=getchar();
bool flag=1 ;
if (c=='-' )
{
flag=0 ;
}
while (c<='9' &&c>='0' )
{
x=x*10 +c-'0' ;
c=getchar();
}
if (!flag)x=-x;
}
ll exgcd(ll a,ll b,ll& x,ll& y)
{
if (!b)
{
x=1 ;
y=0 ;
return a;
}
ll r=exgcd(b,a%b,y,x);
y-=a/b*x;
return r;
}
bool linear_equation(ll a,ll b,ll ca,ll cb,ll& ans)
{
ll x,y,d;
ll c=ca+cb;
d=exgcd(a,b,x,y);
if (c%d)return false ;
ll k=c/d;
ll g=b/d;
if (g<0 )g=-g;
g*=a;
x*=k;y*=k;
ans=a*x-cb;
ans=(ans%g+g)%g;
return true ;
}
int dir[4 ][2 ]={1 ,1 ,-1 ,1 ,1 ,-1 ,-1 ,-1 };
int main(){
ll n,m,k;
scanf ("%lld %lld %lld" ,&n,&m,&k);
while (k--){
ll a,b;
scanf ("%lld %lld" ,&a,&b);
ll ans=(ll)1e18 ;
ll x,y,d,xx;
for (int i=0 ;i<4 ;i++)
if (linear_equation(2 *m,-2 *n,dir[i][0 ]*a,dir[i][1 ]*b,xx))
ans=min(ans,xx);
if (ans==(ll)1e18 )puts ("-1" );
else printf ("%lld\n" ,ans);
}
return 0 ;
}
D. Dense Subsequence
题意:给一个数m和字母字符串s,从s中选择一些位置,要求每连续m个字母的子串都有一个被选中的位置。把这些位置的字符选出来重排列后使得字典序最小?
分析:一开始的时候,随便乱做,看漏了很多性质。后来才发现只需要找到一个最小的字母k(k表示某个字母,并不一定是k),能够使得小于k的位置和某一部分等于k的位置。这些位置存在于任何一个m连续子串之中。其中小于k的字母必须按照原串中的个数输出,然后等于k的字母按照贪心从前往后(这里写法很精妙,我一开始写的不好)。反正就只有26个字母,那么我们就是枚举一下字母k
#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std ;
#define maxn 100000+10
#define SIZE 10000+5
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define clr(x,y) memset(x,y,sizeof(x))
#define rep(i,n) for(int i=0;i<(n);i++)
#define repf(i,a,b) for(int i=(a);i<=(b);i++)
#define pii pair<int,int>
#define mp make_pair
#define FI first
#define SE second
#define IT iterator
#define PB push_back
#define Times 10
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const double eps = 1e-14 ;
const double pi = acos (-1.0 );
const ll mod = 10007 ;
const int inf = 0x3f3f3f3f ;
const ll INF = (ll)1e18 +300 ;
const double delta = 0.98 ;
inline void RI(int & x)
{
x=0 ;
char c=getchar();
while (!((c>='0' &&c<='9' )||c=='-' ))c=getchar();
bool flag=1 ;
if (c=='-' )
{
flag=0 ;
}
while (c<='9' &&c>='0' )
{
x=x*10 +c-'0' ;
c=getchar();
}
if (!flag)x=-x;
}
char dat[maxn];
int n,m,num[300 ];
int solve(int x){
int pre=-1 ,posx=-1 ,cnt=0 ;
for (int i=0 ;i<n;i++){
if (dat[i]<x)pre=posx=i;
if (dat[i]==x)posx=i;
if (i==pre+m){
if (posx==pre)return -1 ;
cnt++;
pre=posx;
}
}
return cnt;
}
int main(){
scanf ("%d %s" ,&m,dat);
n=strlen (dat);
for (int i=0 ;i<n;i++)num[dat[i]]++;
for (int i='a' ;i<='z' ;i++){
int x=solve(i);
if (x!=-1 ){
for (int j='a' ;j<i;j++)
for (int k=0 ;k<num[j];k++)
putchar (j);
for (int j=0 ;j<x;j++)
putchar (i);
puts ("" );
return 0 ;
}
}
return 0 ;
}