2017.7.22小测
7.22test
NOIP2016 模拟赛
——那些年,我们学过的文化课
啧啧,虽然是怀着不爆零的心思去考的试,不过这分说实话也是有点丑了⊙﹏⊙
不过没事,每一次考试都是一次教训,希望下次能够考得稍微好点吧嘻嘻
加油吧~
T1
1.背单词
(word.c/cpp/pas)
【题目描述】
fqk 退役后开始补习文化课啦, 于是他打开了英语必修一开始背单词。 看着满篇的单词非常头疼, 而每次按照相同的顺序背效果并不好,于是 fqk 想了一种背单词的好方法!他把单词抄写到一个 n 行 m 列的表格里,然后每天背一行或者背一列。他的复习计划一共有 k 天,在k 天后, fqk 想知道,这个表格中的每个单词,最后一次背是在哪一天呢?
【输入格式】
第一行三个整数 k m n , , 。
接下来 k 行,每行的格式可能如下:
1。r ,表示当前天 fqk 背了第 r 行的单词。
2。c ,表示当前天 fqk 背了第 c 列的单词。
【输出格式】
输出包含 n 行, 每行 m 个整数, 表示每个格子中的单词最后一次背是在哪天,如果这个单词没有背过,则输出 0 。
【输入样例】
3 3 3
1 2
2 3
1 3
【输出样例】
0 0 2
1 1 2
3 3 3
【数据范围】
对于 % 30 的数据, 1000 , , k m n 。
对于 % 100 的数据, 100000 , 100000 , 5000 , k m n m n 。
【时空限制】
对于每个测试点,时间限制为 s 1 ,空间限制为 MB 512 。
思路:
这题可以直接打暴力的w,只需要在输入的数据里面判断一下是行还是列即可
坑点:
记住要输出比较靠后的那个
上代码:
1)我敲的是特别裸的暴力,纯暴力,无脑暴力
这样都50.。。。
厉害了(秘技——傻逼暴力!!!):
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <cmath>
using namespace std;
const int N = 5050;
const int M = 5050;
int n,m,k;//n 行 m 列
int r[N],c[M];
inline int reads()
{
int x=0,f=1;char ch=getchar();
while(ch<'0' || ch>'9')
{if(ch=='-') f=-1;ch=getchar();}
while(ch>='0' && ch<='9')
{x=10*x+ch-'0';ch=getchar();}
return x*f;
}
int main()
{
freopen("word.in","r",stdin);
freopen("word.out","w",stdout);
// scanf("%d%d%d",&n,&m,&k);
n=reads(),m=reads(),k=reads();
for(int i=1,nu,b;i<=k;++i)
{
// scanf("%d%d",&nu,&b);
nu=reads(),b=reads();
if(nu==1)
r[b]=i;
else
c[b]=i;
}
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
if(r[i]>c[j])
printf("%d ",r[i]);
else
printf("%d ",c[j]);
printf("\n");
}
return 0;
}
2)正解
#include <algorithm> #include <iostream> #include <cstring> #include <string> #include <cstdio> #include <cmath> #include <ctime> using namespace std; const int N = 5050; const int M = 5050; int n,m,k;//n 行 m 列 int r[N],c[M]; inline int reads() { int x=0,f=1;char ch=getchar(); while(ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();} while(ch>='0' && ch<='9') {x=10*x+ch-'0';ch=getchar();} return x*f; } int main() { freopen("word.in","r",stdin); freopen("word.out","w",stdout); // scanf("%d%d%d",&n,&m,&k); n=reads(),m=reads(),k=reads(); for(int i=1,nu,b;i<=k;++i) { // scanf("%d%d",&nu,&b); nu=reads(),b=reads(); if(nu==1) r[b]=i; else c[b]=i; } for(int i=1;i<=n;++i) { for(int j=1;j<=m;++j) if(r[i]>c[j]) printf("%d ",r[i]); else printf("%d ",c[j]); printf("\n"); } return 0; }
T2
2.脱水缩合
(merge.c/cpp/pas)
【题目描述】
fqk 退役后开始补习文化课啦, 于是他打开了生物必修一开始复习蛋白质,他回想起了氨基酸通过脱水缩合生成肽键,具体来说,一个氨基和一个羧基会脱去一个水变成一个肽键。于是他脑洞大开,给你出了这样一道题:
fqk 将给你 6 种氨基酸和 m 个脱水缩合的规则,氨基酸用
' a' , ' b' , 'c ' , 'd ' , 'e ' , 'f '表示,每个规则将给出两个字符串 t s, ,其中|t |=1 , |s |=2 ,表示 s 代表的两个氨基酸可以通过脱水缩合变成 t 。然后请你构建一个长度为 n ,且仅由 ' a' , ' b' , 'c ' , 'd ' , 'e ' , 'f ' 构成的氨基酸序列,如果这个序列的前两个氨基酸可以进行任意一种脱水缩合, 那么就可以脱水缩合,脱水缩合后序列的长度将 1 ,这样如果可以进行 1 n 次脱水缩合,最终序列的长度将变为 1 ,我们可以认为这是一个蛋白质,如果最后的蛋白质为 ' 'a , 那么初始的序列就被称为一个好的氨基酸序列。 fqk 想让你求出有多少好的氨基酸序列。
注:题目描述可能与生物学知识有部分偏差(即氨基酸进行脱水缩合后应该是肽链而不是新的氨基酸),请以题目描述为准。
【输入格式】
第一行两个整数 q n, 。
接下来 q 行,每行两个字符串 t s, ,表示一个脱水缩合的规则。
【输出格式】
一行,一个整数表示有多少好的氨基酸序列。
【输入样例】
3 5
ab a
cc c
ca a
ee c
ff d
【输出样例】
4
【样例解释】
一共有四种好的氨基酸序列,其脱水缩合过程如下:
"abb" "ab" "a"
"cab" "ab" "a"
"cca" "ca" "a"
"eea" "ca" "a"
【数据范围】
对于 % 100 的数据, 36 , 6 2 q n 。数据存在梯度。
【时空限制】
对于每个测试点,时间限制为 2s ,空间限制为 512 MB
思路:
先找组成的字符串,然后判断是否能够变幻出来,如果可以,ans++,这样就避免了重复的情况。
坑点:
进行覆盖的时候只需要覆盖一个位置即可,回溯也只需要回溯被修改的位置,其他保持不变
教训:
不会的东西就别去乱搞,比如set
上代码:
1)瞎鸡巴乱搞233(就搞了20qwq)
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <cmath>
#include <set>
using namespace std;
const int Q = 50;
int n,q,ans;
int ru[7];
bool vis[27];
set<string>orz;
struct B {
string u;
char v;
}e[Q];
inline int reads()
{
int x=0,f=1;char ch=getchar();
while(ch<'0' || ch>'9')
{if(ch=='-') f=-1;ch=getchar();}
while(ch>='0' && ch<='9')
{x=10*x+ch-'0';ch=getchar();}
return x*f;
}
void dfs(string noww,char f,int nowl,bool flag)
{
if(nowl==n)
{
orz.insert(noww);
return;
}
int rp,cp;
for(int i=1;i<=q;++i)
{
if(e[i].v==f)
{
char pre=e[i].u[0],nxt=e[i].u[1];
rp=pre-96,cp=nxt-96;
///you
if(flag)
{
int len=noww.length();
char tmp[8];
tmp[0]=e[i].u[0],tmp[1]=e[i].u[1];
for(int j=0;j<len;++j)
tmp[j+len]=noww[j+1];
noww=tmp;
if(ru[rp])
dfs(noww,pre,nowl+1,0);
if(ru[cp])
dfs(noww,nxt,nowl+1,1);
}
///zuo
else
{
int len=noww.length();
char tmp[8];
for(int j=0;j<len-1;++j)
tmp[j]=noww[j];
tmp[len]=e[i].u[0],tmp[len+1]=e[i].u[1];
noww=tmp;
if(ru[rp])
dfs(noww,pre,nowl+1,0);
if(ru[cp])
dfs(noww,nxt,nowl+1,1);
}
}
}
}
int main()
{
freopen("merge.in","r",stdin);
freopen("merge.out","w",stdout);
// scanf("%d%d",&n,&q);
n=reads(),q=reads();
for(int i=1,x;i<=q;++i)
{
cin>>e[i].u>>e[i].v;
x=e[i].v-96;
ru[x]++;
if(x==1)
ans++;
}
if(!ans || n==1)
{
printf("0\n");
return 0;
}
for(int i=1;i<=q;++i)
{
if(e[i].v=='a')
{
dfs(e[i].u,e[i].u[0],2,0);
dfs(e[i].u,e[i].u[1],2,1);
}
}
printf("%d\n",orz.size());
return 0;
}
2)正解
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int K = 50;
char s[K][3],t[K][3];
char a[8];
int n,q,ans;
bool vis[K];
bool judge(int x)
{
//成功构造出一个
if(x==n && a[n]=='a')
return true;
for(int i=1;i<=q;++i)
//若能够进行转化
if(s[i][1]==a[x] && s[i][2]==a[x+1])
{
int tmp=a[x+1];
//进行覆盖
a[x+1]=t[i][1];
bool flag=judge(x+1);
//回溯,多寻找几组可行方案
a[x+1]=tmp;
//若成功,return
if(flag)
return true;
}
return false;
}
void dfs(int x)
{
if(x==n+1)
{
if(judge(1))
ans++;
return;
}
for(int i=0;i<6;++i)
{
a[x]=i+'a';
dfs(x+1);
}
}
int main()
{
freopen("merge.in","r",stdin);
freopen("merge.out","w",stdout);
scanf("%d%d",&n,&q);
for(int i=1;i<=q;++i)
{
scanf("%s",s[i]+1);
scanf("%s",t[i]+1);
}
dfs(1);
cout<<ans;
return 0;
}
T3
3.一次函数
(fx.c/cpp/pas)
【题目描述】
fqk 退役后开始补习文化课啦, 于是他打开了数学必修一开始复习函数, 他回想起了一次函数都是 f(x)=kx+b 的形式, 现在他给了你 n 个一次函数 fi(x)=kix+bi, 然后将给你 m 个操作, 操作将以如下格式给出:
M . 1 i k b ,把第 i 个函数改为 fi(x)=kx+b。
Q . 2 l r x ,询问fr(fr-1(...fl(x)))mod 1000000007 的值。
【输入格式】
第一行两个整数 n , m ,代表一次函数的数量和操作的数量。
接下来 n 行,每行两个整数,表示ki ,bi 。
接下来 m 行,每行的格式为 M i k b 或 Q l r x 。
【输出格式】
对于每个操作 Q ,输出一行表示答案。
【输入样例】
5 5
4 2
3 6
5 7
2 6
7 5
Q 1 5 1
Q 3 3 2
M 3 10 6
Q 1 4 3
Q 3 4 4
【输出样例】
1825
17
978
98
【数据范围】
对于 % 30 的数据, n,m<=1000 ,。
对于 % 100 的数据, n,m<=200000,k b,x<1000000007
【时空限制】
对于每个测试点,时间限制为 2s ,空间限制为 512MB
思路:
1)考场上想到了线段树,但是因为懒不想敲,拼命的去想第二个,结果俩题都炸掉了。。。
2)正解就是线段树
上代码:
1)我考场上写的就不需要贴出来啦~\(≧▽≦)/~毕竟不好看还没分
(雾
2)正解:
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#define LL long long
#define lson root<<1
#define rson root<<1|1
using namespace std;
const int N = 200005;
const int Mod = 1000000007;
int n,m,k[N],b[N];
struct C {
int l,r;
LL mul,sum;
}t[N<<2];
inline int reads()
{
int x=0,f=1;char ch=getchar();
while(ch<'0' || ch>'9')
{if(ch=='-') f=-1;ch=getchar();}
while(ch>='0' && ch<='9')
{x=10*x+ch-'0';ch=getchar();}
return x*f;
}
inline C unions(C le,C ri)
{
C ret;
ret.l=le.l,ret.r=ri.r;
ret.mul=le.mul*ri.mul%Mod;
ret.sum=(le.sum*ri.mul%Mod+ri.sum)%Mod;
return ret;
}
inline void update(int root)
{
t[root]=unions(t[lson],t[rson]);
}
inline void build(int root,int l,int r)
{
if(l==r)
{
t[root].l=t[root].r=l;
t[root].sum=b[l];
t[root].mul=k[l];
return;
}
int mid=(l+r)>>1;
build(lson,l,mid);
build(rson,mid+1,r);
update(root);
}
inline void modify(int root,int x,int ki,int bi)
{
int l=t[root].l,r=t[root].r;
if(l==r)
{
t[root].sum=bi;
t[root].mul=ki;
return;
}
int mid=(l+r)>>1;
if(x<=mid)
modify(lson,x,ki,bi);
else
modify(rson,x,ki,bi);
update(root);
}
inline C query(int root,int l,int r)
{
int ll=t[root].l,rr=t[root].r;
if(ll==l && rr==r)
return t[root];
int mid=(ll+rr)>>1;
if(r<=mid)
return query(lson,l,r);
else
if(l>mid)
return query(rson,l,r);
else
return unions(query(lson,l,mid),query(rson,mid+1,r));
}
int main()
{
freopen("fx.in","r",stdin);
freopen("fx.out","w",stdout);
n=reads(),m=reads();
for(int i=1;i<=n;++i)
k[i]=reads(),b[i]=reads();
build(1,1,n);
for(int i=1;i<=m;++i)
{
char w[5];
cin>>w;
if(w[0]=='M')
{
int x=reads(),ki=reads(),bi=reads();
modify(1,x,ki,bi);
}
else
{
int l=reads(),r=reads(),x=reads();
C ans=query(1,l,r);
printf("%I64d\n",(ans.mul*x%Mod+ans.sum)%Mod);
}
}
return 0;
}