tozangezan's diary

勝手にソースコードをコピペして利用しないでください。

Codeforces Round #348 (VK Cup 2016 Round 2, Div. 1 Edition)

何だこのセットは......。難問が誰にも存在しないセットだと、簡単が速いから勝ててしまう。

A B C D E F Place
00:13 00:06 00:34 (+1) 00:48 - - 4th

A:
逆からやるだけ。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<stdlib.h>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
int p[11000][4];
int mat[110][110];
int main(){
	int a,b,c;scanf("%d%d%d",&a,&b,&c);
	for(int i=0;i<c;i++){
		scanf("%d%d",&p[i][0],&p[i][1]);
		p[i][1]--;
		if(p[i][0]==3){
			scanf("%d%d",&p[i][2],&p[i][3]);
			p[i][2]--;
		}
	}
	for(int i=c-1;i>=0;i--){
		if(p[i][0]==3){
			mat[p[i][1]][p[i][2]]=p[i][3];
		}else if(p[i][0]==2){
			int tmp=mat[a-1][p[i][1]];
			for(int j=a-1;j>0;j--){
				mat[j][p[i][1]]=mat[j-1][p[i][1]];
			}
			mat[0][p[i][1]]=tmp;
		}else{
			int tmp=mat[p[i][1]][b-1];
			for(int j=b-1;j>0;j--){
				mat[p[i][1]][j]=mat[p[i][1]][j-1];
			}
			mat[p[i][1]][0]=tmp;
		}
	}
	for(int i=0;i<a;i++){
		for(int j=0;j<b;j++){
			if(j)printf(" ");
			printf("%d",mat[i][j]);
		}
		printf("\n");
	}
}

B:
偶奇ごとに持っておけば、偶数奇数それぞれの中では平行移動してるだけ。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<stdlib.h>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
int ret[1100000];
int main(){
	int a,b;scanf("%d%d",&a,&b);
	int p1=0;
	int p2=1;
	while(b--){
		int c;scanf("%d",&c);
		if(c==1){
			int d;scanf("%d",&d);
			p1+=d;
			p2+=d;
			if(p1<0)p1+=a;
			if(p2<0)p2+=a;
			if(p1>=a)p1-=a;
			if(p2>=a)p2-=a;
			
		}else{
			p1^=1;
			p2^=1;
		}
	}
	for(int i=0;i<a/2;i++){
		ret[(p1+i*2)%a]=i*2+1;
		ret[(p2+i*2)%a]=i*2+2;
	}
	for(int i=0;i<a;i++){
		if(i)printf(" ");
		printf("%d",ret[i]);
	}
	printf("\n");
}

C:
手元で二次方程式を解く・sqrtの中身を負にしないように

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<stdlib.h>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
double A[110000];
double B[110000];

double x[110000];
double y[110000];
int main(){
	int a;scanf("%d",&a);
	for(int i=0;i<a;i++)scanf("%lf",A+i);
	for(int i=0;i<a;i++)scanf("%lf",B+i);
	double p1=0;
	double p2=0;
	for(int i=0;i<a;i++)p2+=B[i];
	for(int i=0;i<a-1;i++){
		p1+=A[i];
		p2-=B[i];
		y[i]=0.5*((p1-p2+1)+sqrt(max(0.0,(p1-p2+1)*(p1-p2+1)-4.0*p1)));
		x[i]=0.5*((p1-p2+1)-sqrt(max(0.0,(p1-p2+1)*(p1-p2+1)-4.0*p1)));
	}
	x[a-1]=y[a-1]=1;
	for(int i=a-1;i>0;i--){
		x[i]-=x[i-1];
		y[i]-=y[i-1];
	}
	for(int i=0;i<a;i++){
		if(i)printf(" ");
		printf("%.12f",x[i]);
	}
	printf("\n");
	for(int i=0;i<a;i++){
		if(i)printf(" ");
		printf("%.12f",y[i]);
	}
	printf("\n");
	
}

D:
追加する数ごとに独立で、内部でも座標圧縮してBITするだけ...。残り2問と比べてあまりにも簡単すぎる。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<stdlib.h>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
int x[110000];
int b[110000];
int t[110000];
int z[110000];
vector<int>q[110000];
int bit[110000];
int sz;
int sum(int a,int b){
	if(a)return sum(0,b)-sum(0,a-1);
	int ret=0;
	for(;b>=0;b=(b&(b+1))-1)ret+=bit[b];
	return ret;
}
void add(int a,int b){
	for(;a<sz;a|=a+1)bit[a]+=b;
}
int z2[110000];
int ans[110000];
int main(){
	int a;scanf("%d",&a);
	for(int i=0;i<a;i++){
		scanf("%d%d%d",b+i,t+i,x+i);
		z[i]=x[i];
	}
	std::sort(z,z+a);
	for(int i=0;i<a;i++){
		int at=lower_bound(z,z+a,x[i])-z;
		q[at].push_back(i);
	}
	for(int i=0;i<a;i++){
		if(q[i].size()){
			sz=q[i].size();
			for(int j=0;j<q[i].size();j++){
				z2[j]=t[q[i][j]];
			}
			std::sort(z2,z2+sz);
			for(int j=0;j<q[i].size();j++){
				int ind=lower_bound(z2,z2+sz,t[q[i][j]])-z2;
				if(b[q[i][j]]==1){
					add(ind,1);
				}else if(b[q[i][j]]==2){
					add(ind,-1);
				}else{
					ans[q[i][j]]=sum(0,ind);
				}
			}
			for(int j=0;j<sz;j++)bit[j]=0;
		}
	}
	for(int i=0;i<a;i++){
		if(b[i]!=3)continue;
		printf("%d\n",ans[i]);
	}
}

F:
虚無。
Black box linear algebraを勉強する(これも虚無)か、虚無を実装するか。木分解でもうまくいきそうに見えるけどどうなんだこれ。

第3回 Dwangoからの挑戦状 Finals

えええ....。せっかくの優勝チャンスを逃した。

A B C D Place
118:47 70:40 (+2) 47:52 (+2) - 5th

A:
ずっと前から見てて解けないと思ってトイレにいったら後ろからやるだけだった。こういうのが遅いのはダメでしょ

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<stdlib.h>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
char in[100];
int dp[60][60][60][2];
int v[60][60][60];
void solve(int a,int b,int c){
	if(v[a][b][c])return ;
	v[a][b][c]=1;
	// +
 
	dp[a][b][c][0]=-mod;
	dp[a][b][c][1]=mod;
	int rem=c;
	if(in[b]!='+')rem--;
	for(int i=a;i<b;i++){
		for(int j=0;j<=rem;j++){
			solve(a,i,j);
			solve(i+1,b-1,rem-j);
			if(dp[a][i][j][0]>-mod&&dp[i+1][b-1][rem-j][0]>-mod){
				dp[a][b][c][0]=max(dp[a][i][j][0]+dp[i+1][b-1][rem-j][0],dp[a][b][c][0]);
				dp[a][b][c][1]=min(dp[a][i][j][1]+dp[i+1][b-1][rem-j][1],dp[a][b][c][1]);	
			}
		}
	}
	// -
	rem=c;
	if(in[b]!='-')rem--;
	for(int i=a;i<b;i++){
		for(int j=0;j<=rem;j++){
			solve(a,i,j);
			solve(i+1,b-1,rem-j);
			if(dp[a][i][j][0]>-mod&&dp[i+1][b-1][rem-j][0]>-mod){
				dp[a][b][c][0]=max(dp[a][i][j][0]-dp[i+1][b-1][rem-j][1],dp[a][b][c][0]);
				dp[a][b][c][1]=min(dp[a][i][j][1]-dp[i+1][b-1][rem-j][0],dp[a][b][c][1]);	
			}
		}
	}
	if(a==b){
		if(c){
			dp[a][b][c][0]=max(dp[a][b][c][0],9);
			dp[a][b][c][1]=min(dp[a][b][c][1],0);
			
		}
		if('0'<=in[a]&&in[a]<='9'){
			dp[a][b][c][0]=max(dp[a][b][c][0],in[a]-'0');
			dp[a][b][c][1]=min(dp[a][b][c][1],in[a]-'0');
		}
	}
}
int main(){
	int a;scanf("%d%s",&a,in);
	int n=strlen(in);
	solve(0,n-1,a);
	if(dp[0][n-1][a][0]==-mod){
		printf("NG\n");return 0;
	}else printf("OK\n%d\n",dp[0][n-1][a][0]);
}

B:
はじめてのMo。速くできるのはわかるけども、速くしなくても定数倍で1/2くらいの割合の人が通るみたいなのは、経験のあるwriterがやるはずないですよね。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<stdlib.h>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
int si[11000];
 
int v[110000];
vector<pair<int,int> >ss[110000];
long long ret=1;
long long inv[2200000];
long long ans[110000];
int SQ=300;
vector<pair<pair<int,int>,int> > ev[350]; // rm, lm, id
int main(){
 
	int a,b;scanf("%d%d",&a,&b);
	inv[1]=1;
	for(int i=2;i<2200000;i++){
		inv[i]=(mod-(mod/i)*inv[mod%i]%mod)%mod;
	}
	for(int i=0;i<a;i++){
		int p;scanf("%d",&p);
		for(int j=2;j*j<=p;j++){
			if(p%j==0){
				int cur=0;
				while(p%j==0){
					p/=j;cur++;
				}
				ss[i].push_back(make_pair(j,cur));
				v[j]=1;
			}
		}
		if(p>1){
			v[p]=1;
			ss[i].push_back(make_pair(p,1));
		}
	}
	int sz=0;
	for(int i=0;i<110000;i++){
		if(v[i])v[i]=sz++;
	}
	for(int i=0;i<b;i++){
		int p,q;scanf("%d%d",&p,&q);p--;
		ev[p/SQ].push_back(make_pair(make_pair(q,p),i));
	}
	for(int i=0;i<350;i++){
		std::sort(ev[i].begin(),ev[i].end());
	}
	for(int i=0;i<350;i++){
		int l=i*SQ;
		int r=i*SQ;
		for(int j=0;j<sz;j++)si[j]=1;
		ret=1;
		for(int j=0;j<ev[i].size();j++){
			int p=ev[i][j].first.second;
			int q=ev[i][j].first.first;
			int id=ev[i][j].second;
			if(r<q){
				while(r<q){
					for(int k=0;k<ss[r].size();k++){
						int to=ss[r][k].first;
						int am=ss[r][k].second;
						ret=(ret*(si[v[to]]+am)%mod*inv[si[v[to]]])%mod;
						si[v[to]]+=am;
					}
					r++;
				}
			}
			if(l>p){
				while(l>p){
					for(int k=0;k<ss[l-1].size();k++){
						int to=ss[l-1][k].first;
						int am=ss[l-1][k].second;
						ret=(ret*(si[v[to]]+am)%mod*inv[si[v[to]]])%mod;
						si[v[to]]+=am;
					}
					l--;
				}
			}
			if(r>q){
				while(r>q){
					r--;
					for(int k=0;k<ss[r].size();k++){
						int to=ss[r][k].first;
						int am=-ss[r][k].second;
						ret=(ret*(si[v[to]]+am)%mod*inv[si[v[to]]])%mod;
						si[v[to]]+=am;
					}
				}
			}
			if(l<p){
				while(l<p){
					for(int k=0;k<ss[l].size();k++){
						int to=ss[l][k].first;
						int am=-ss[l][k].second;
						ret=(ret*(si[v[to]]+am)%mod*inv[si[v[to]]])%mod;
						si[v[to]]+=am;
					}
					l++;
				}
			}
			ans[id]=ret;
		}
	}
	for(int i=0;i<b;i++)printf("%lld\n",ans[i]);
}

C:
点を含む丸を121回で見つけたら、丸をどのくらい上に動かしても大丈夫か、どのくらい右に動かしても大丈夫かを二分探索で求めて。円の交点のどっちか1つが答え。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<stdlib.h>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
char in[110];
const double EPS = 1e-10;
const double INF = 1e+10;
const double PI = acos(-1);
int sig(double r) { return (r < -EPS) ? -1 : (r > +EPS) ? +1 : 0; }
inline double ABS(double a){return max(a,-a);}
struct Pt {
	double x, y;
	Pt() {}
	Pt(double x, double y) : x(x), y(y) {}
	Pt operator+(const Pt &a) const { return Pt(x + a.x, y + a.y); }
	Pt operator-(const Pt &a) const { return Pt(x - a.x, y - a.y); }
	Pt operator*(const Pt &a) const { return Pt(x * a.x - y * a.y, x * a.y + y * a.x); }
	Pt operator-() const { return Pt(-x, -y); }
	Pt operator*(const double &k) const { return Pt(x * k, y * k); }
	Pt operator/(const double &k) const { return Pt(x / k, y / k); }
	double ABS() const { return sqrt(x * x + y * y); }
	double abs2() const { return x * x + y * y; }
	double arg() const { return atan2(y, x); }
	double dot(const Pt &a) const { return x * a.x + y * a.y; }
	double det(const Pt &a) const { return x * a.y - y * a.x; }
};
double tri(const Pt &a, const Pt &b, const Pt &c) { return (b - a).det(c - a); }
pair<Pt,Pt> pCC(Pt a, double r, Pt b, double s) {
	double d = (b - a).ABS();
	double x = (d * d + r * r - s * s) / (d * 2);
	Pt e = (b - a) / d, w = e * Pt(0, 1) * sqrt(max(r * r - x * x, 0.0));
	return make_pair(a + e * x - w, a + e * x + w);
}
Pt c;
int main(){
	bool ok=false;
	for(int i=0;i<=10;i++){
		if(ok)break;
		for(int j=0;j<=10;j++){
			if(ok)break;
			printf("%d %d\n",i*100000,j*100000);fflush(stdout);
			scanf("%s",in);
			if(in[1]=='o')return 0;
			if(in[1]=='l'){
				ok=true;
				c=Pt(i*100000,j*100000);
			}
		}
	}
	double left=0;
	double right=200000;
	for(int i=0;i<35;i++){
		double M=(left+right)/2;
		printf("%.12f %.12f\n",c.x+M,c.y);
		fflush(stdout);
		scanf("%s",in);
		if(in[1]=='o')return 0;
		if(in[1]=='l')left=M;
		else right=M;
	}
	double X=c.x+left;
	left=0;
	right=200000;
	for(int i=0;i<35;i++){
		double M=(left+right)/2;
		printf("%.12f %.12f\n",c.x,c.y+M);
		fflush(stdout);
		scanf("%s",in);
		if(in[1]=='o')return 0;
		if(in[1]=='l')left=M;
		else right=M;
	}
	double Y=c.y+left;
	pair<Pt,Pt> tt=pCC(Pt(X,c.y),100000,Pt(c.x,Y),100000);
	int t1=tt.first.x-0.5;
	int t2=tt.first.y-0.5;
	for(int i=0;i<2;i++)for(int j=0;j<2;j++){
		printf("%d %d\n",t1+i,t2+j);fflush(stdout);scanf("%s",in);
		if(in[1]=='o')return 0;
	}
	t1=tt.second.x-0.5;
	t2=tt.second.y-0.5;
	for(int i=0;i<2;i++)for(int j=0;j<2;j++){
		printf("%d %d\n",t1+i,t2+j);fflush(stdout);scanf("%s",in);
		if(in[1]=='o')return 0;
	}
}

D:
どうみても遅延更新segtreeであることはわかるしだいたいこういうことがしたいというのはわかるけども、能力が至らず解けなかった。こういう負け方(敗因が練習不足であるのがはっきりしてるケース)が一番ダメ。

Codeforces Round #349 (Div. 1)

いつもと同じ死に方。成長が見られない。相変わらず注意力が灰底辺。

A B C D E Place
00:48 (+1) 00:35 (+4) 01:59 (+1) - - 59th

A:
メモ化再帰するだけ。メモ化し忘れて1TLE。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<stdlib.h>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
char in[11000];
int dp[11000][3];
set<string>S;
char tmp[4];
int n;
int solve(int a,int b){
	if(~dp[a][b])return dp[a][b];
	if(a==n)return dp[a][b]=1;
	int t=0;
	if(a<=n-2){
		if(b!=0||in[a]!=in[a-2]||in[a+1]!=in[a-1]){
			int res=solve(a+2,0);
			if(res){
				t=res;
				tmp[2]=0;tmp[0]=in[a];tmp[1]=in[a+1];string tt=tmp;S.insert(tt);
			}
		}	
	}
	if(a<=n-3){
		if(b!=1||in[a]!=in[a-3]||in[a+1]!=in[a-2]||in[a+2]!=in[a-1]){
			int res=solve(a+3,1);
			if(res){
				t=res;
				tmp[3]=0;tmp[0]=in[a];tmp[1]=in[a+1];tmp[2]=in[a+2];string tt=tmp;S.insert(tt);
			}
		}	
	}
	return dp[a][b]=t;
}
int main(){
	scanf("%s",in);
	n=strlen(in);
	for(int i=0;i<11000;i++)for(int j=0;j<3;j++)
		dp[i][j]=-1;
	for(int i=5;i<=n;i++){
		solve(i,2);
	}
	printf("%d\n",(int)(S.size()));
	for(set<string>::iterator it=S.begin();it!=S.end();it++)printf("%s\n",(*it).c_str());
}

B:
なにも変な要素がないのにひたすらWA。頭が悪すぎる。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<stdlib.h>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
vector<int>g[3100];
int dist[3100][3100];
int L[3100][3];
int R[3100][3];
int main(){
	int a,b;scanf("%d%d",&a,&b);
	for(int i=0;i<b;i++){
		int p,q;scanf("%d%d",&p,&q);p--;q--;
		g[p].push_back(q);
	}
	for(int i=0;i<a;i++){
		for(int j=0;j<a;j++)dist[i][j]=-1;
		queue<int>Q;
		Q.push(i);
		dist[i][i]=0;
		while(Q.size()){
			int at=Q.front();Q.pop();
			for(int j=0;j<g[at].size();j++){
				int to=g[at][j];
				if(dist[i][to]==-1){
					dist[i][to]=dist[i][at]+1;
					Q.push(to);
				}
			}
		}
	}
	for(int i=0;i<a;i++){
		L[i][0]=L[i][1]=L[i][2]=-1;
		for(int j=0;j<a;j++){
			if(i==j)continue;
			if(dist[j][i]==-1)continue;
			if(L[i][0]==-1||dist[j][i]>dist[L[i][0]][i]){
				L[i][2]=L[i][1];
				L[i][1]=L[i][0];
				L[i][0]=j;
			}else if(L[i][1]==-1||dist[j][i]>dist[L[i][1]][i]){
				L[i][2]=L[i][1];
				L[i][1]=j;
			}else if(L[i][2]==-1||dist[j][i]>dist[L[i][2]][i]){
				L[i][2]=j;
			}
		}
	}
	for(int i=0;i<a;i++){
		R[i][0]=R[i][1]=R[i][2]=-1;
		for(int j=0;j<a;j++){
			if(i==j)continue;
			if(dist[i][j]==-1)continue;
			if(R[i][0]==-1||dist[i][j]>dist[i][R[i][0]]){
				R[i][2]=R[i][1];
				R[i][1]=R[i][0];
				R[i][0]=j;
			}else if(R[i][1]==-1||dist[i][j]>dist[i][R[i][1]]){
				R[i][2]=R[i][1];
				R[i][1]=j;
			}else if(R[i][2]==-1||dist[i][j]>dist[i][R[i][2]]){
				R[i][2]=j;
			}
		}
	}
	int A,B,C,D;
	int bs=0;
	for(int i=0;i<a;i++){
		for(int j=0;j<a;j++){
			for(int k=0;k<3;k++)for(int l=0;l<3;l++){
				if(L[i][k]==-1||R[j][l]==-1||dist[i][j]==-1)continue;
				if(i==j||i==R[j][l]||j==L[i][k]||L[i][k]==R[j][l])continue;
				if(bs<dist[L[i][k]][i]+dist[i][j]+dist[j][R[j][l]]){
					bs=dist[L[i][k]][i]+dist[i][j]+dist[j][R[j][l]];
					A=L[i][k];B=i;C=j;D=R[j][l];
				}
			}
		}
	}
	set<int>S;
	S.insert(A);
	S.insert(B);
	S.insert(C);
	S.insert(D);
	if(S.size()!=4){
		while(1);
	}
	printf("%d %d %d %d\n",A+1,B+1,C+1,D+1);
}

C:
nCkテーブルをsqrt(N)段ごとに作っておいて一行ずつ下がるやつに係数をつけただけ。一箇所-1し忘れ。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<stdlib.h>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
char in[110000];
int n;
int sz=0;
pair<pair<int,int>,int>p[110000];
int ans[110000];
int SQ=300;
long long fact[110000];
long long inv[110000];
long long finv[110000];
long long C(int a,int b){
	return fact[a]*finv[b]%mod*finv[a-b]%mod;
}
long long val[110000];
long long sum[110000];
long long p26[110000];
long long p25[110000];
int main(){
	fact[0]=finv[0]=1;
	p26[0]=1;
	p25[0]=1;
	inv[1]=1;
	for(int i=2;i<110000;i++)inv[i]=(mod-(mod/i)*inv[mod%i]%mod)%mod;
	for(int i=1;i<110000;i++){
		fact[i]=fact[i-1]*i%mod;
		finv[i]=finv[i-1]*inv[i]%mod;
		p26[i]=p26[i-1]*26%mod;
		p25[i]=p25[i-1]*25%mod;
	}
	int a;scanf("%d",&a);
	scanf("%s",in);
	n=strlen(in);
	while(a--){
		int t;scanf("%d",&t);
		if(t==1){
			scanf("%s",in);
			n=strlen(in);
		}else{
			int b;scanf("%d",&b);
			p[sz]=make_pair(make_pair(b,n),sz);
			sz++;
		}
	}
	std::sort(p,p+sz);
	int at=0;
	for(int i=0;i<340;i++){
		long long ks=1;
		for(int j=i*SQ;j>=0;j--){
			val[j]=C(i*SQ,j)*ks;
			ks=ks*25%mod;
		}
		for(int j=0;j<=i*SQ;j++){
			sum[j]=val[j];
			if(j)sum[j]=(sum[j]+sum[j-1])%mod;
		}
		while(at<sz&&p[at].first.first<(i+1)*SQ){

			if(p[at].first.first<p[at].first.second){
				at++;continue;
			}
			long long now=sum[min(i*SQ,p[at].first.second-1)];

			int r=min(i*SQ,p[at].first.second-1);
			for(int j=0;j<p[at].first.first%SQ;j++){
				if(r==p[at].first.second-1){
					now=now*26%mod;
					now=(now+mod-C(i*SQ+j,r)*p25[i*SQ+j-r]%mod)%mod;
				}else{
					now=now*26%mod;
					r++;
				}
			}

			ans[p[at].second]=(p26[p[at].first.first]+mod-now)%mod;
			at++;
		}
	}
	for(int i=0;i<sz;i++)printf("%d\n",ans[i]);
}

Codeforces Round #352 (Div. 1)

心が折れた。
灰コーダー並みの注意力だったのも悪いけど、サンプルも弱いし罠も多すぎだと思う。

A B C D E Place
00:28 (+1) 00:14 (+2) -5 - - 105th

A:
嫌なケースが多すぎる。returnを忘れた。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<stdlib.h>
using namespace std;
const long long mod=1000010007;
const long long inf=mod*mod;
double x[3];
double y[3];
double X[110000];
double Y[110000];
double dist(double dx,double dy){
	return sqrt(dx*dx+dy*dy);
}
pair<double,int> ta[110000];
pair<double,int> tb[110000];
int main(){
	for(int i=0;i<3;i++){
		scanf("%lf%lf",x+i,y+i);
	}
	int a;scanf("%d",&a);
	for(int i=0;i<a;i++){
		scanf("%lf%lf",X+i,Y+i);
	}
	if(a==1){
		printf("%.12f\n",min(dist(X[0]-x[0],Y[0]-y[0]),dist(X[0]-x[1],Y[0]-y[1]))+dist(X[0]-x[2],Y[0]-y[2]));
		return 0;
	}
	double ret=0;
	for(int i=0;i<a;i++){
		ret+=dist(X[i]-x[2],Y[i]-y[2])*2;
		ta[i]=make_pair(dist(X[i]-x[0],Y[i]-y[0])-dist(X[i]-x[2],Y[i]-y[2]),i);
		tb[i]=make_pair(dist(X[i]-x[1],Y[i]-y[1])-dist(X[i]-x[2],Y[i]-y[2]),i);
	}
	double ad=99999999999999.9;
	std::sort(ta,ta+a);
	std::sort(tb,tb+a);
	for(int i=0;i<2;i++)for(int j=0;j<2;j++){
		if(ta[i].second==tb[j].second)continue;
		ad=min(ta[i].first+tb[j].first,ad);
	}
	ad=min(ad,min(ta[0].first,tb[0].first));
	printf("%.12f\n",ret+ad);
}

B:
奇数のときは最小1とかいう明確な罠。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<stdlib.h>
using namespace std;
const long long mod=1000010007;
const long long inf=mod*mod;
int c[510000];
int main(){
	int a,b;
	scanf("%d%d",&a,&b);
	long long sum=0;
	for(int i=0;i<a;i++){
		scanf("%d",c+i);
		sum+=c[i];
	}
	std::sort(c,c+a);
	int left=0;
	int right=mod;
	while(left+1<right){
		int M=(left+right)/2;
		long long cur=0;
		for(int i=0;i<a;i++){
			if(c[i]<M)cur+=M-c[i];
		}
		if(b<cur){
			right=M;
		}else left=M;
	}
	int q1=left;
	left=0;
	right=mod;
	while(left+1<right){
		int M=(left+right)/2;
		long long cur=0;
		for(int i=0;i<a;i++){
			if(c[i]>M)cur+=c[i]-M;
		}
		if(b<cur){
			left=M;
		}else right=M;
	}
	int q2=right;
	if(q1>q2)q1=q2;
	if(q2-q1==0&&sum%a)q2++;
	printf("%d\n",q2-q1);
}

C:
二重に誤読していた。が解けるものには見えない。

Codeforces Round #359 (Div. 1)

面白いかどうかはさておき、教育された感がある。普段Aからやってると抜かされるのでBからやったら大失敗した。

A B C D E Place
01:01 00:48 - 01:35 - 57th

A:
やるだけ。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<stdlib.h>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
int dp[2][1<<7][2];
int p7[24];
int main(){
	int a,b;scanf("%d%d",&a,&b);
	int A=0;
	int B=0;
	int c=a-1;int d=b-1;
	while(c){
		c/=7;
		A++;
	}
	while(d){
		d/=7;
		B++;
	}
	p7[0]=1;
	for(int i=1;i<24;i++)p7[i]=p7[i-1]*7;
	a--;b--;
	if(!A)A++;
	if(!B)B++;
	dp[0][0][0]=1;
	for(int i=0;i<A+B;i++){
		int t=i%2;
		for(int j=0;j<(1<<7);j++)dp[!t][j][0]=dp[!t][j][1]=0;
		for(int j=0;j<(1<<7);j++){
			for(int k=0;k<2;k++){
				if(!dp[t][j][k])continue;
		//		printf("%d %d %d: %d\n",i,j,k,dp[i][j][k]);
				for(int l=0;l<7;l++){
					if(j&(1<<l))continue;
					int tk=k;
					if(i<A){
						if(k==0&&a/p7[A-i-1]%7<l)continue;
						else if(a/p7[A-i-1]%7>l)tk=1;
					}else{
						if(k==0&&b/p7[A+B-i-1]%7<l)continue;
						else if(b/p7[A+B-i-1]%7>l)tk=1;
					}
					if(i==A-1)tk=0;
					dp[!t][j+(1<<l)][tk]+=dp[t][j][k];
				}
			}
		}
	}
	int ret=0;
	for(int i=0;i<(1<<7);i++)for(int j=0;j<2;j++)ret+=dp[(A+B)%2][i][j];
	printf("%d\n",ret);
}

B:
慣れないdsu on treeを練習した。慣れない。あと定数倍がきつすぎ
ポインタに造詣がない人には、dsu on treeのあの書き方はデマ一より有用?

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<stdlib.h>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
vector<int>g[310000];
int sz[310000];
int num;
int L[310000];
int R[310000];
int conv[310000];
int nx[310000];
void dfs(int a){
	sz[a]=1;
	L[a]=num;
	conv[num]=a;
	int mn=0;

	num++;
	for(int i=0;i<g[a].size();i++){
		dfs(g[a][i]);
		sz[a]+=sz[g[a][i]];
		if(mn<sz[g[a][i]]){
			mn=sz[g[a][i]];
			nx[a]=i;
		}
	}
	R[a]=num;
}
int ans[310000];
set<pair<pair<int,int>,int> > S;
set<pair<pair<int,int>,int> > T;
int mx[310000];
void solve(int a,int b){
	int to=-1;

	for(int i=0;i<g[a].size();i++){
		mx[a]=max(mx[a],sz[g[a][i]]);
		if(nx[a]==i){
			to=g[a][i];continue;
		}
		solve(g[a][i],0);

	}
	if(~to)solve(to,1);
	for(int i=0;i<g[a].size();i++){
		if(to==g[a][i])continue;
		solve(g[a][i],1);
	}
	if(!~ans[a]){

	T.insert(make_pair(make_pair(mx[a],sz[a]),a));
	S.insert(make_pair(make_pair(sz[a],mx[a]),a));
	int del=0;
	for(set<pair<pair<int,int>,int> > ::iterator it=S.begin();it!=S.end();it++){
		if((*it).first.first*2<sz[a])del++;
		else break;
	}
	for(int i=0;i<del;i++){
		pair<pair<int,int>,int> tmp=*(S.begin());
		S.erase(tmp);
		swap(tmp.first.first,tmp.first.second);
		T.erase(tmp);
	}
		ans[a]=(*(T.begin())).second;
	}
//	printf("%d: %d %d %d\n",a,T.begin()->first.first,T.begin()->first.second,T.begin()->second);
	if(b==0){
		for(int i=L[a];i<R[a];i++){
			T.erase(make_pair(make_pair(mx[conv[i]],sz[conv[i]]),conv[i]));
			S.erase(make_pair(make_pair(sz[conv[i]],mx[conv[i]]),conv[i]));
		}
	}
}
int main(){
	int a,b;scanf("%d%d",&a,&b);
	for(int i=0;i<a-1;i++){
		int p;scanf("%d",&p);p--;
		g[p].push_back(i+1);
	}
	for(int i=0;i<a;i++)ans[i]=-1;
	dfs(0);
	solve(0,1);
	while(b--){
		int p;scanf("%d",&p);p--;printf("%d\n",ans[p]+1);
	}
}

D:
計算量的には O(n log n+kn)で余裕そうに見えるがO(kn)パートが定数4のついたsetを使うやつで結構重そう、というか実際重い。
Time Limitの設定が総じて雑...?

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<stdlib.h>
using namespace std;
const long long mod=1000010007;
const long long inf=mod*mod;
int r[110000];
int c[110000];
pair<int,int>p[110000];
pair<int,int>ev[210000];
long long ret[110000];
int main(){
	int a,b;
	scanf("%d%d",&a,&b);
	for(int i=0;i<a;i++){
		scanf("%d%d",r+i,c+i);
		ev[i*2+1]=make_pair(r[i],i+1);
		ev[i*2]=make_pair(r[i]+b,-i-1);
		p[i]=make_pair(c[i],r[i]);
	}
	std::sort(p,p+a);
	std::sort(ev,ev+a*2);
	int last=-mod;
	set<pair<int,pair<int,int> > > S;
	for(int i=0;i<a*2;i++){
	//	printf("%d: %d %d\n",i,ev[i].first,ev[i].second);
		if(i==0||ev[i].first!=ev[i-1].first){
			long long ks=ev[i].first-last;
			int las=-mod;
			int cnt=0;
			for(set<pair<int,pair<int,int> > >::iterator it=S.begin();it!=S.end();it++){
				if(it==S.begin()||((*it).first!=las)){

					if(cnt)ret[cnt]+=((long long)(*it).first-las)*ks;
					las=(*it).first;
				}
				cnt+=(*it).second.first;
			}
			last=ev[i].first;
		}
		if(ev[i].second>0){
			S.insert(make_pair(c[ev[i].second-1],make_pair(1,ev[i].second)));
			S.insert(make_pair(c[ev[i].second-1]+b,make_pair(-1,ev[i].second)));
		}else{
			S.erase(make_pair(c[-ev[i].second-1],make_pair(1,-ev[i].second)));
			S.erase(make_pair(c[-ev[i].second-1]+b,make_pair(-1,-ev[i].second)));
		}
	}
	for(int i=1;i<=a;i++){
		if(i!=1)printf(" ");
		printf("%I64d",ret[i]);
	}
	printf("\n");
}

Codeforces Round #360 (Div. 1)

初全完。全完ゲーはHack上乗せ勝負なのでVirtual Participation勢には不利。

A B C D E Place
00:07 00:17 (+1) 00:27 00:50 01:39 16th

A:
よくある二色塗りのUFを書いたら他の人に取り残されたんだけど、簡単な解法があるのかな。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<stdlib.h>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
int UF[210000];
int FIND(int a){
	if(UF[a]<0)return a;
	return UF[a]=FIND(UF[a]);
}
void UNION(int a,int b){
	a=FIND(a);b=FIND(b);if(a==b)return;UF[a]+=UF[b];UF[b]=a;
}
vector<int>A;
vector<int>B;
int v[210000];
int main(){
	int a,b;scanf("%d%d",&a,&b);
	for(int i=0;i<a*2;i++)UF[i]=-1;
	for(int i=0;i<b;i++){
		int p,q;scanf("%d%d",&p,&q);p--;q--;
		UNION(p,q+a);
		UNION(q,p+a);
	}
	for(int i=0;i<a;i++){
		if(FIND(i)==FIND(i+a)){
			printf("-1\n");return 0;
		}
	}
	for(int i=0;i<a;i++){
		if(v[FIND(i)]==0&&v[FIND(i+a)]==0){
			v[FIND(i)]=1;
			v[FIND(i+a)]=-1;
			A.push_back(i);
		}else{
			if(v[FIND(i)]==1||v[FIND(i+a)]==-1){
				v[FIND(i)]=1;
				v[FIND(i+a)]=-1;
				A.push_back(i);
			}else{
				v[FIND(i)]=-1;
				v[FIND(i+a)]=1;
				B.push_back(i);
			}
		}
	}
	printf("%d\n",(int)A.size());
	for(int i=0;i<A.size();i++){
		if(i)printf(" ");printf("%d",A[i]+1);
	}
	printf("\n");
	printf("%d\n",(int)B.size());
	for(int i=0;i<B.size();i++){
		if(i)printf(" ");printf("%d",B[i]+1);
	}
	printf("\n");
}

B:
素因数が足りてるか。素数でないものを見てしまい1WA。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<stdlib.h>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
int c[1100000];
long long gcd(long long a,long long b){
	while(a){
		b%=a;swap(a,b);
	}
	return b;
}
long long lcm(long long a,long long b){
	return a/gcd(a,b)*b;
}
vector<pair<int,int> > v;
int main(){
	int a,b;scanf("%d%d",&a,&b);
	for(int i=0;i<a;i++)scanf("%d",c+i);
	for(int i=2;i<=b;i++){
		if(b%i)continue;
		int e=0;
		while(b%i==0){
			e++;
			b/=i;
		}
		v.push_back(make_pair(i,e));
	}
	bool ok=true;
	for(int i=0;i<v.size();i++){
		bool OK=false;
		for(int j=0;j<a;j++){
			int tmp=c[j];
			int cur=0;
			while(tmp%v[i].first==0){
				tmp/=v[i].first;
				cur++;
			}
			if(cur>=v[i].second){
				OK=true;break;
			}
		}
		if(!OK){ok=false;break;}
	}
	if(ok)printf("Yes\n");
	else printf("No\n");
}

C:
合計をKにする用としなくてもいい用の2つの要素があればよい。これも上位勢は速すぎ

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<stdlib.h>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
int dp[510][510];
int c[510];
int main(){
	int a,b;scanf("%d%d",&a,&b);
	for(int i=0;i<a;i++)scanf("%d",c+i);
	vector<int>ans;
	dp[0][0]=1;
	for(int i=0;i<a;i++){
		for(int j=b;j>=0;j--){
			for(int k=b;k>=0;k--){
				if(dp[j][k]){
					if(j+c[i]<=b){
						dp[j+c[i]][k+c[i]]=1;
						dp[j+c[i]][k]=1;
					}
				}
			}
		}
	}
	for(int i=0;i<=b;i++)if(dp[b][i])ans.push_back(i);
	printf("%d\n",(int)ans.size());
	for(int i=0;i<ans.size();i++){
		if(i)printf(" ");
		printf("%d",ans[i]);
	}
	printf("\n");
}

D:
強引にunion findの自明解を送ったら5974ms/6000msで通ってしまった...。非再帰Union-Findにすればもっと速くなるのではないかと考えると、Time Limitが雑すぎる。
どうせ想定解も変なsqrtテクか永続あたりを使ってオーダー落とすUnion-Findなんでしょ。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<stdlib.h>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
int dp[510][510];
int c[510];
int main(){
	int a,b;scanf("%d%d",&a,&b);
	for(int i=0;i<a;i++)scanf("%d",c+i);
	vector<int>ans;
	dp[0][0]=1;
	for(int i=0;i<a;i++){
		for(int j=b;j>=0;j--){
			for(int k=b;k>=0;k--){
				if(dp[j][k]){
					if(j+c[i]<=b){
						dp[j+c[i]][k+c[i]]=1;
						dp[j+c[i]][k]=1;
					}
				}
			}
		}
	}
	for(int i=0;i<=b;i++)if(dp[b][i])ans.push_back(i);
	printf("%d\n",(int)ans.size());
	for(int i=0;i<ans.size();i++){
		if(i)printf(" ");
		printf("%d",ans[i]);
	}
	printf("\n");
}

E:
それぞれの頂点からスタートして自分に戻るループの最小長を求めて置いて、短いものから逆にたどっていくgreedy。強連結成分分解のライブラリは作りましょう......

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<stdlib.h>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;

vector<int>g[5100];
vector<int>rev[5100];
int v[5100];
int num[5100];
int conv[5100];
int scc[5100];
int fi[5100];
int ss[5100];
int cur;
void dfs(int a){
	for(int i=0;i<g[a].size();i++){
		if(v[g[a][i]])continue;
		v[g[a][i]]=1;
		dfs(g[a][i]);
	}
	conv[a]=cur;
	num[cur++]=a;
}
void dfs2(int a){
	scc[a]=cur;
	ss[cur]++;
	for(int i=0;i<rev[a].size();i++){
		if(v[rev[a][i]])continue;
		v[rev[a][i]]=1;
		dfs2(rev[a][i]);
	}
}
int len[5100];
int dp[2][5100];
int st;
void dfs3(int a,int b){
	v[a]=1;
	for(int i=0;i<g[a].size();i++){
		if(g[a][i]==st){
			if(len[st]==-1)len[st]=b+1;
			else if(len[st]>b+1)len[st]=b+1;
		}
		if(v[g[a][i]])continue;
		dfs3(g[a][i],b+1);
	}
}
vector<int>G[5100];
int g2[5100][5100];
int used[5100];
pair<pair<int,int>,int> q[5100];
int main(){
	int a,b;scanf("%d%d",&a,&b);
	for(int i=0;i<b;i++){
		int p,q;scanf("%d%d",&p,&q);p--;q--;
		g[p].push_back(q);
		rev[q].push_back(p);
	}
	for(int i=0;i<a;i++){
		if(v[i])continue;
		v[i]=1;
		dfs(i);
	}
	cur=0;
	for(int i=0;i<a;i++)v[i]=0;
	for(int i=a-1;i>=0;i--){
		if(v[num[i]])continue;
		v[num[i]]=1;
		fi[cur]=num[i];
		dfs2(num[i]);
		cur++;
	}
	for(int i=0;i<a;i++){
		len[i]=-1;
		st=i;
		for(int j=0;j<a;j++)v[j]=0;

		dfs3(i,0);
	//printf("%d: %d\n",i,len[i]);
		q[i]=make_pair(make_pair(len[i],conv[i]),i);
	}
	std::sort(q,q+a);
	for(int i=0;i<a;i++){
		for(int j=0;j<rev[i].size();j++){
			if(scc[i]!=scc[rev[i][j]]){
				g2[scc[i]][scc[rev[i][j]]]=1;
			}
		}
	}
	for(int i=0;i<cur;i++){
		for(int j=0;j<cur;j++){
			if(g2[i][j])G[i].push_back(j);
		}
	}
	int ret=0;
	for(int i=0;i<a;i++){
		int at=q[i].second;
		int cost=q[i].first.first;
		if(used[scc[at]])continue;
		if(cost!=-1){
			ret+=998*cost+1;
		}
		used[scc[at]]=1;
		queue<int>Q;
		Q.push(scc[at]);
		while(Q.size()){
			int now=Q.front();Q.pop();
			ret+=ss[now];
			for(int j=0;j<G[now].size();j++){
				if(used[G[now][j]])continue;
				used[G[now][j]]=1;
				Q.push(G[now][j]);
			}
		}
	}
	printf("%d\n",ret);
}

Codeforces Round #362 (Div. 1)

解けたのに虚しくなる意味不明なセット。面白くはない。

A B C D E F Place
00:10 (+1) 00:17 00:38 01:14 - - 37th

A:
辺を全部mapで更新する。何も考えずにやったらオーバーフローした。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<stdlib.h>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
map<long long,long long> m;
long long u[110];
long long v[110];
int main(){
	int a;scanf("%d",&a);
	while(a--){
		int t;scanf("%d",&t);
		if(t==1){
			long long p,q,r;scanf("%I64d%I64d%I64d",&p,&q,&r);
			int sa=0;
			int sb=0;
			while(p){
				u[sa++]=p;
				p/=2;
			}
			while(q){
				v[sb++]=q;
				q/=2;
			}
			int sl=0;
			for(int i=0;i<min(sa,sb);i++){
				if(u[sa-1-i]==v[sb-1-i])sl++;
				else break;
			}
			for(int i=0;i<sa-sl;i++){
				m[u[i]]+=r;
			}
			for(int i=0;i<sb-sl;i++){
				m[v[i]]+=r;
			}
		}else{
			long long p,q;scanf("%I64d%I64d",&p,&q);
			int sa=0;
			int sb=0;
			while(p){
				u[sa++]=p;
				p/=2;
			}
			while(q){
				v[sb++]=q;
				q/=2;
			}
			int sl=0;
			long long ret=0;
			for(int i=0;i<min(sa,sb);i++){
				if(u[sa-1-i]==v[sb-1-i])sl++;
				else break;
			}
			for(int i=0;i<sa-sl;i++){
				if(m.count(u[i]))ret+=m[u[i]];
			}
			for(int i=0;i<sb-sl;i++){
				if(m.count(v[i]))ret+=m[v[i]];
			}
			printf("%I64d\n",ret);
		}
	}
}

B:
いい加減こういうの見飽きた。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<stdlib.h>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
vector<int>g[110000];
int sz[110000];
double dp[110000];
void dfs(int a){
	sz[a]=1;
	for(int i=0;i<g[a].size();i++){
		dfs(g[a][i]);
		sz[a]+=sz[g[a][i]];
	}
}
void calc(int a,double b){
	dp[a]=b;
	for(int i=0;i<g[a].size();i++){
		calc(g[a][i],b+1+(sz[a]-1-sz[g[a][i]])*0.5);
	}
}
int main(){
	int a;scanf("%d",&a);
	for(int i=0;i<a-1;i++){
		int p;scanf("%d",&p);p--;
		g[p].push_back(i+1);
	}
	dfs(0);
	calc(0,0);
	for(int i=0;i<a;i++){
		if(i)printf(" ");
		printf("%.12f",dp[i]+1);
	}
	printf("\n");
}

C:
手で数学をするだけ。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<stdlib.h>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
long long b[110000];
long long d3=(mod+1)/3;
long long d2=(mod+1)/2;
long long pw(long long a,long long b){
	long long ret=1;
	while(b){
		if(b%2)ret=ret*a%mod;
		b/=2;
		a=a*a%mod;
	}
	return ret;
}
int main(){
	int a;
	scanf("%d",&a);
	for(int i=0;i<a;i++)scanf("%I64d",b+i);
	bool gu=false;
	for(int i=0;i<a;i++)if(b[i]%2==0)gu=true;
	long long tmp=pw(2,b[0]);
	for(int i=1;i<a;i++)tmp=pw(tmp,b[i]);
	tmp=tmp*d2%mod;
	long long bs;
	if(gu)bs=(tmp+1)%mod;
	else bs=(tmp+mod-1)%mod;
	bs=bs*d3%mod;
	printf("%d/%d\n",(int)bs,(int)tmp);
}

D:
Trie上でCow Relaysするだけ。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<stdlib.h>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
int c[210];
char in[210][210];
int len[210];
struct Trie{
	int chi[26];
	int sc;
	Trie(){for(int i=0;i<26;i++)chi[i]=-1;sc=0;}
};
Trie pool[210];
char st[210];
int n;
int to[210][26];
void dfs(int a,int b){
	for(int i=0;i<26;i++){
		if(pool[a].chi[i]==-1)continue;
		st[b]='a'+i;
		dfs(pool[a].chi[i],b+1);
	}
	for(int i=0;i<n;i++){
		if(len[i]>b)continue;
		bool ok=true;
		for(int j=0;j<len[i];j++){
			if(in[i][len[i]-1-j]!=st[b-1-j]){ok=false;break;}
		}
		if(ok)pool[a].sc+=c[i];
	}
	for(int i=0;i<26;i++){
		st[b]=i+'a';
		bool ok=false;
		for(int j=0;j<=b;j++){
			int now=0;
			for(int k=j;k<=b;k++){
				if(pool[now].chi[st[k]-'a']==-1){now=-1;break;}
				now=pool[now].chi[st[k]-'a'];
			}
			if(now!=-1){
				ok=true;to[a][i]=now;break;
			}
		}
		if(!ok)to[a][i]=0;
	}
}
long long dp[210][210][210];
long long val[210][410];
long long las[210][210];
int main(){
	int a;
	long long b;
	scanf("%d%I64d",&a,&b);
	n=a;
	for(int i=0;i<a;i++)scanf("%d",c+i);
	for(int i=0;i<a;i++){
		scanf("%s",in[i]);
		len[i]=strlen(in[i]);
	}
	int sz=1;
	for(int i=0;i<a;i++){
		int at=0;
		for(int j=0;in[i][j];j++){
			if(pool[at].chi[in[i][j]-'a']==-1){
				pool[at].chi[in[i][j]-'a']=sz++;
				at=sz-1;
			}else at=pool[at].chi[in[i][j]-'a'];
		}
	}
	dfs(0,0);
	for(int i=0;i<sz;i++){
		for(int j=0;j<210;j++)for(int k=0;k<210;k++)dp[i][j][k]=-mod;
		dp[i][0][i]=0;
		for(int j=0;j<sz;j++){
			for(int k=0;k<sz;k++){
				for(int l=0;l<26;l++){
					dp[i][j+1][to[k][l]]=max(dp[i][j+1][to[k][l]],dp[i][j][k]+pool[to[k][l]].sc);
				}
			}
		}
	}
	long long ret=0;
	for(int i=0;i<sz;i++){
		for(int j=0;j<410;j++){
			val[i][j]=-inf;
			if(b-j<0)continue;
			for(int k=1;k<=sz;k++){
				if(dp[i][k][i]<0)continue;
				val[i][j]=max(val[i][j],(b-j)/k*dp[i][k][i]);
			}
		}
	}
	if(b<sz){
		for(int i=0;i<sz;i++)ret=max(ret,dp[0][b][i]);
		printf("%I64d\n",ret);
		return 0;
	}
	for(int i=0;i<sz;i++){
		for(int j=0;j<sz;j++){
			las[i][j]=-inf;
			for(int k=0;k<sz;k++)las[i][j]=max(las[i][j],dp[i][j][k]);
		}
	}
	for(int i=0;i<sz;i++){
		for(int j=0;j<sz;j++)for(int k=0;k<sz;k++){
			ret=max(ret,dp[0][j][i]+val[i][j+k]+las[i][k]);
		}
	}
	printf("%I64d\n",ret);
}

F:
二分探索で、中でそれぞれの辺から中に伸ばすとどの範囲なら対応可能かというのを求めておけば、ある辺からスタートするとどこまでいけるかというのがわかり、判断可能でO(N^2 log X)なんだろうけど、実装量も多すぎるし、JAGの幾何と同様全く面白くない。