标签:随便搞搞
第三套题
出题人:faebdc
金牌爷的题这么神竟然还有学长AK了QAQ
题目全都是CF上的 T1 D T2 E T3 D
神犇地址:faebdc学长的blog
试题下载地址
数据下载地址
话说题解的ppt用色果然还是faebdc神犇的常用配色= =
虚化色块喷涂拼接
T1 CF305D Olya ans Graph
原题可以自己去CF找
学长给的是翻译后题面
【问题描述】
Olya 有一张 n 个点、 m 条边的有向无权图, 所有点从 1 到 n 标号。 现在 Olya 想知道
有多少种添加有向边的方案(任意添加) ,使得该图满足下列条件:
1、 从点 i 出发,可以到达点 i+1, i+2, …,n。
2、 任意从 u 到 v 的有向边满足不等式: u
3、 两点之间最多有一条边。
4、 对于一对点 i、 j(i
5、 对于一对点 i、 j(i
我们认为两种添加边的方案不同,当且仅当存在至少一对点 i、 j(i
一条从 i 连向 j 的边,而另一张图中没有。
帮助 Olya! 由于要求的答案可能太大,将答案对 1000000007 取模后输出。
【输入格式】
第一行包含三个用空格隔开的整数, n,m,k。 接下来 m 行描述原图的有向边。第 i 行
包含一对用空格隔开的整数 ui,vi,表示第 i 条有向边从 ui 连向 vi。
【输出格式】
输出一个整数,即答案模 1000000007。
【样例输入】
7 8 2
1 2
2 3
3 4
3 6
4 5
4 7
5 6
6 7
【样例输出】
2
【数据规模和约定】
保证输入中任意一对点 ui,vi 之间最多有一条边。并且保证输入中给出的 ui 不下降。
如果有多条有向边从 ui 出发, 那么这些边将按照 vi 升序给出。 保证原图中任意从 u 到 v
的有向边满足不等式: u
对于 30%的数据,保证 n,m
对于 60%的数据,保证 n,m
对于 100%的数据, 2
题目简洁易懂.由题目我们不难看出该图中只可能有两种边
为i->i+1,i->i+k+1
剩下的就很好办了
开始乱搞!
这两天来第一个AC的题QwQ
感人至深
我的代码(注释里解释很全)
//AC code by CreationAugust沙茶
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define P 1000000007
#define MAXM 100010
#define MAXN 1000010
#define MAXINT 0x7fffffff
using namespace std;
int n,m,k;
int u[MAXM],v[MAXM];
int pre[MAXN]={1};
bool flag[MAXN];
int maxn=-MAXINT,minn=MAXINT;
long long ans=1;
long long num;
int check()//可执行性检测(随便起个名别在意QwQ)
{
for (int i=1;i<=m;i++)
{
if (v[i]-u[i]>1)
{
if (v[i]-u[i]-1!=k) return 0;//读入的这些边都是不符合条件的
//存在这些边的情况下不可能有解 ( ⊙ o ⊙ )
maxn=max(maxn,u[i]);
minn=min(minn,u[i]);
flag[u[i]]=1;//记录合法的边起点,暂时叫他可执行点好了→v→
}
}
for (int i=1;i<=m;i++)
{
if (v[i]-u[i]>1)
if (maxn-u[i]>k) return 0;//一条路径上不可能
//同时有两条i->i+k+1的边存在
//这种情况也不合法 ╮(╯▽╰)╭
}
return 1;
}
int main()
{
freopen("olya.in","r",stdin);
freopen("olya.out","w",stdout);
scanf("%d%d%d",&n,&m,&k);
for (int i=1;i<=m;i++)
scanf("%d%d",&u[i],&v[i]);
for (int i=1;i<=n;i++)
pre[i]=(pre[i-1]*2)%P;
//每个点(除了太靠后的不考虑)
//都可以向外连两种边0-0
//所以先预处理出裸的方案数量好了www
if (!check()) //有可能输入不合法
{
cout<<"0"<<endl;
return 0;
}
//开始乱搞!
for (int i=1;i<=n;i++)
if (flag[i]) num++;//把i打成u[i]调了半天QAQ
if (maxn==-MAXINT)//可执行点有可能不存在ヾ(0ω0)
{
int x=min(k,n-k-1);
for (int i=0;i<x;i++)
{
ans+=pre[i];
ans%=P;
}
int temp=n-k-1-k;
ans=(ans%P+(pre[k]*temp%P))%P;
}
else
{
int t2=min(n-k-1,minn+k);//n-k-1或者minn+k之后
//就不能连i->i+k+1的边了QwQ
int t1=max(maxn-k,1);
for (int i=t2;i>=t1;i--)
{
if (flag[i])
num--;
else
{
int temp=min(min(i-1,k-maxn+i),k);
ans=(ans%P+pre[temp-num])%P;//除掉他们剩下的都是可用的方案
}
}
}
cout<<ans<<endl;
}
这是标程
//std by faebdc神犇 果然强大竟然短那么多QAQ
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 1050000;
const int MOD = 1000000007;
int n,m,k;
int cc,minz,maxz;
long long ans=0;
int erci[N];
int main()
{
freopen("olya.in","r",stdin);
freopen("olya.out","w",stdout);
int i,j;
int a,b;
scanf("%d%d%d",&n,&m,&k);
erci[0]=1;
for(i=1;i<=n;i++)
erci[i]=(erci[i-1]<<1)%MOD;
for(i=1;i<=m;i++)
{
scanf("%d%d",&a,&b);
if(a+1==b)
continue;
if(b-a!=k+1)
{
printf("0\n");
return 0;
}
if(!cc)
minz=a;
cc++;
maxz=a;
}
n-=k+1;
if(n<=0)
{
printf("1\n");
return 0;
}
if(!cc)
{
if(n<=k+1)
ans=erci[n];
else
{
ans=erci[k];
ans*=n-k+1;
ans%=MOD;
}
printf("%d\n",ans);
return 0;
}
if(minz+k<maxz)
{
printf("0\n");
return 0;
}
for(i=max(1,maxz-k);i<minz;i++)
ans+=erci[min(k-cc,n-i-cc)];
ans+=erci[min(k+1-cc,n-minz+1-cc)];
ans%=MOD;
printf("%d\n",ans);
return 0;
}
T2 CF249E Endless Matrix
【问题描述】
有一个矩阵,里面有连续的数字,从 1 开始。若 a_{i,j}
且仅当满足以下条件之一:
1. max(i,j)
2. max(i,j)=max(t,k) 且 j
3. max(i,j)=max(t,k) , j=k 且 i
例如前 36 个数字形成的矩阵:
1 2 5 10 17 26
4 3 6 11 18 27
9 8 7 12 19 28
16 15 14 13 20 29
25 24 23 22 21 30
36 35 34 33 32 31
对于给定的 x_1,y_1,x_2 和 y_2 (x_1
【输入格式】
第一行一个正整数 t,表示数据组数。
接下来 t 行每行四个正整数 x_1,y_1,x_2 和 y_2。
【输出格式】
对每一个询问输出答案。 如果答案超过 10 位, 输出三个”. “, 然后输出答案的后十位。
否则直接输出答案。
【样例输入】
51
1 1 1
2 2 3 3
2 3 5 6
100 87 288 2002
4 2 5 4
【样例输出】
1
24
300
…5679392764
111
【数据规模和约定】
对于 30%的数据, t
对于 60%的数据, t
对于 100%的数据, t
果断暴力骗了30分= =
后来去想优化还是没来得及写出来
60分只要单纯枚举行列就可以了不用逐个枚举
满分做法看了我瞎了
竟然对表格分块我也真是醉了
之前没学分块昨天学姐才刚讲了讲知道了能把线性表分块
表格竟然也可以OTZ
暴力我就不贴了QwQ
//std by faebdc 这高精写的我也醉了
#include<cstdio>
#include<cstring>
const int N = 100;
const int M = 100000;
long long ans[N];
long long now[N];
long long jie[N];
void clear(long long x[])
{
int i;
for(i=1;i<=x[0];i++)
x[i]=0;
x[0]=0;
}
void add(long long x[],int y)
{
x[1]+=y;
int i=1;
while(x[i]>=M)
{
x[i+1]+=x[i]/M;
x[i]%=M;
i++;
}
if(x[0]<i)
x[0]=i;
}
void mul(long long x[],int y)
{
int i;
for(i=1;i<=x[0];i++)
x[i]*=y;
for(i=1;i<=x[0];i++)
{
x[i+1]+=x[i]/M;
x[i]%=M;
}
while(x[x[0]+1])
{
x[0]++;
x[x[0]+1]+=x[x[0]]/M;
x[x[0]]%=M;
}
while(x[0] && !x[x[0]])
x[0]--;
}
void jia(long long x[],long long y[])
{
int i;
if(x[0]<y[0])
x[0]=y[0];
for(i=1;i<=x[0];i++)
x[i]+=y[i];
for(i=1;i<=x[0];i++)
{
x[i+1]+=x[i]/M;
x[i]%=M;
}
while(x[x[0]+1])
{
x[0]++;
x[x[0]+1]+=x[x[0]]/M;
x[x[0]]%=M;
}
}
void jian(long long x[],long long y[])
{
int i;
for(i=1;i<=x[0];i++)
x[i]-=y[i];
for(i=1;i<=x[0];i++)
{
if(x[i]<0)
{
x[i]+=M;
x[i+1]--;
}
}
while(x[0] && !x[x[0]])
x[0]--;
}
void divide(long long x[],int y)
{
int i;
long long has=0;
for(i=x[0];i>0;i--)
{
has*=M;
has+=x[i];
x[i]=has/y;
has%=y;
}
while(x[0] && !x[x[0]])
x[0]--;
}
void print(long long x[])
{
int i;
int a=x[1];
int b=x[2];
if(x[0]==1)
printf("%d\n",a);
else if(x[0]==2)
{
printf("%d",b);
printf("%05d\n",a);
}
else
{
printf("...%05d",b);
printf("%05d\n",a);
}
}
void yici(long long x[],int y)
{
clear(x);
add(x,y);
mul(x,y+1);
divide(x,2);
}
void erci(long long x[],int y)
{
clear(x);
add(x,y);
mul(x,y+1);
mul(x,(y<<1)+1);
divide(x,6);
}
void sanci(long long x[],int y)
{
clear(x);
add(x,y);
mul(x,y);
mul(x,y+1);
mul(x,y+1);
divide(x,4);
}
void same(int a,int b,int c,int d)
{
int s=a-1;
d-=s;
yici(now,s);
mul(now,d);
mul(now,d<<1);
jia(ans,now);
erci(now,d);
mul(now,2);
yici(jie,d);
mul(jie,3);
add(now,d);
jian(now,jie);
mul(now,s<<1);
jia(ans,now);
sanci(now,d);
mul(now,2);
yici(jie,d);
jia(now,jie);
erci(jie,d);
mul(jie,3);
jian(now,jie);
jia(ans,now);
clear(now);
add(now,d);
mul(now,d);
jia(ans,now);
}
void transverse(int a,int b,int c,int d)
{
clear(now);
add(now,a);
mul(now,a<<1);
clear(jie);
add(jie,b-1);
add(jie,d-1);
jian(now,jie);
d=d-b+1;
b=c-a+1;
mul(now,b);
mul(now,d);
divide(now,2);
jia(ans,now);
yici(now,b-1);
mul(now,a<<1);
mul(now,d);
jia(ans,now);
yici(now,b);
mul(now,b*2+1);
erci(jie,b);
mul(jie,2);
jian(now,jie);
clear(jie);
add(jie,b);
mul(jie,b);
jian(now,jie);
mul(now,d);
jia(ans,now);
}
void lengthways(int a,int b,int c,int d)
{
clear(now);
add(now,a);
add(now,c);
c=c-a+1;
a=b-1;
b=d-b+1;
clear(jie);
add(jie,a);
mul(jie,a<<1);
jia(now,jie);
mul(now,c);
divide(now,2);
mul(now,b);
jia(ans,now);
yici(now,b-1);
mul(now,a<<1);
mul(now,c);
jia(ans,now);
yici(now,b);
mul(now,b*2+1);
erci(jie,b);
mul(jie,2);
jian(now,jie);
clear(jie);
add(jie,b);
mul(jie,b);
jian(now,jie);
mul(now,c);
jia(ans,now);
}
void regular(int a,int b,int c,int d)
{
if(a>b)
{
transverse(a,b,c,a-1);
same(a,a,c,d);
}
else if(a<b)
{
lengthways(a,b,b-1,d);
same(b,b,c,d);
}
else
same(a,b,c,d);
}
void rectangle(int a,int b,int c,int d)
{
if(b>=c)
lengthways(a,b,c,d);
else if(a>=d)
transverse(a,b,c,d);
else if(c<d)
{
regular(a,b,c,c);
lengthways(a,c+1,c,d);
}
else if(c>d)
{
regular(a,b,d,d);
transverse(d+1,b,c,d);
}
else
regular(a,b,c,d);
print(ans);
}
void f()
{
memset(ans,0,sizeof ans);
int a,b,c,d;
scanf("%d%d%d%d",&a,&b,&c,&d);
rectangle(a,b,c,d);
}
int main()
{
freopen("matrix.in","r",stdin);
freopen("matrix.out","w",stdout);
int T;
scanf("%d",&T);
while(T--)
f();
return 0;
}
T3 CF342D Xenia and Dominoes
Xenia 非常喜欢拼图。她特别喜欢由多米诺骨牌组成的拼图。下图就是这样的拼图。
一个拼图是一个 3× n 的网格,除掉一些禁止块(图中的黑色正方形),并包含多米
诺骨牌。一个拼图被称作合法当它符合以下条件:
1、每个多米诺骨牌覆盖正好两个非禁止块;
2、没有两个多米诺骨牌覆盖网格上的同一块区域;
3、有且仅有一个非禁止块没被任何多米诺骨牌覆盖(图中的圆点)。
为了使拼图有意义, 拼图必须至少能移动一步。 一步移动是在保证拼图合法的情况下,
把一个多米诺骨牌移到空格子里。 横向的多米诺骨牌只能横向移动, 纵向的多米诺骨牌只
能纵向移动。你不能旋转多米诺骨牌。图中表示了一个合法的移动。
Xenia 有一个 3× n 的带禁止块和一个圆圈标记的网格。 Xenia 还有很多完全一样的多
米诺骨牌。 现在 Xenia 想知道, 如果她把多米诺骨牌放在网格上, 能有多少种不同的合法
的拼图。 同时, Xenia 要求圆圈标记的格子没有被覆盖。 这个拼图还必须至少能移动一次。
帮助 Xenia 统计上述拼图的种数。这个数字可能很大,输出它对 1000000007(109+7)
取模的余数。
【输入格式】
第一行一个整数 n 表示拼图的大小。 接下来 3 行, 每行 n 个字符, 描述这个网格。 “X”
表示禁止块, “. ” 表示非禁止块, “O” 表示它是圆圈标记的。
保证有且仅有一个格子是圆圈标记的。
【输出格式】
输出一个整数,问题的答案对 1000000007(109+7) 取模的余数。
【样例输入】
5
….X
.O…
…X.
【样例输出】
1
【数据规模和约定】
对于 30%的数据, n≤8
对于 60%的数据, n≤1000
对于 90%的数据, n≤50000
对于 100%的数据, n≤2000000
暴力当时都写残了
想了想不改了直接输出0得了说不定能骗到分
没想到一分没有QAQ
90分是插头DP(轮廓线?)(不会写)
100分对90分加了优化,减少常数和内存(比如滚动数组)
反正我是看了题解也不会写…
(一定有人嘲讽你前两天网络课插头DP白学了)
反正我就是弱就是蠢QAQ
//std by faebdc
#include<cstdio>
const int N = 2000500;
const int T = 8;
const int MOD = 1000000007;
const int dir[4][2]={ {0,-1},{-1,0},{0,1},{1,0} };
int dp[2][T];
bool map[N][5];
int ans=0;
int zx,zy;
int n;
int Do()
{
int i,j;
int ii=0;
for(i=0;i<=6;i++)
dp[0][i]=0;
dp[0][7]=1;
for(i=1;i<=n;i++)
{
ii^=1;
int has=7;
if(map[i][1])
has^=1;
if(map[i][2])
has^=2;
if(map[i][3])
has^=4;
for(j=0;j<8;j++)
{
if((j&has)==has)
{
int add=j^has;
dp[ii][j]=dp[ii^1][7^add];
if(add==3 || add==6)
{
dp[ii][j]+=dp[ii^1][7];
if(dp[ii][j]>=MOD)
dp[ii][j]-=MOD;
}
if(add==7)
{
dp[ii][j]+=dp[ii^1][3];
if(dp[ii][j]>=MOD)
dp[ii][j]-=MOD;
dp[ii][j]+=dp[ii^1][6];
if(dp[ii][j]>=MOD)
dp[ii][j]-=MOD;
}
}
else
dp[ii][j]=0;
}
}
return dp[n&1][7];
}
void dfs(int x,int has)
{
if(x>3)
{
if(!has)
return;
if(has&1)
{
ans+=Do();
if(ans>=MOD)
ans-=MOD;
}
else
{
ans-=Do();
if(ans<0)
ans+=MOD;
}
return;
}
dfs(x+1,has);
int tx=dir[x][0];
int ty=dir[x][1];
if(map[zx+tx][zy+ty] && map[zx+tx+tx][zy+ty+ty])
{
map[zx+tx][zy+ty]=0;
map[zx+tx+tx][zy+ty+ty]=0;
dfs(x+1,has+1);
map[zx+tx][zy+ty]=1;
map[zx+tx+tx][zy+ty+ty]=1;
}
}
int main()
{
freopen("xenia.in","r",stdin);
freopen("xenia.out","w",stdout);
int i,j;
scanf("%d",&n);
for(j=1;j<=3;j++)
{
char t;
scanf(" %c",&t);
for(i=1;i<=n;i++)
{
if(t==‘O‘)
{
zx=i;
zy=j;
}
if(t==‘.‘)
map[i][j]=1;
t=getchar();
}
}
dfs(0,0);
printf("%d\n",ans);
return 0;
}
今天虽然没爆零但是估计是RP好罢了QAQ
明天还是要做好爆零的准备QAQ
但是以后至少要把简单暴力分拿到啊!
标签:随便搞搞
原文地址:http://blog.csdn.net/creationaugust/article/details/44020355