Accepts: 567
Submissions: 7005
Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 32768/32768 K (Java/Others)
Problem Description
在本题中,我们只有两种方法计算两个n×n 的矩阵的乘积,第一种为定义法,需要n3 次乘法和(n−1)n2 次加法。第二种为Strassen分治法,仅当n 为偶数时可以使用,需要18(n/2)2 次加法以及再计算7 次大小为(n/2)×(n/2) 的矩阵的乘积。这7 次更小矩阵的乘积也可以选择两种方法之一计算。现假设计算机计算一次加法需要a 单位时间,计算一次乘法需要b 单位时间,其他任何操作不花费时间,问计算两个n×n 的矩阵的乘积至少需要多少时间。输出答案模109+7 的余数。
Input
第一行一个正整数t 表示数据组数(1≤t≤20 )。每组数据包含一行三个正整数n ,a ,b (1≤n≤232 ,n 是2 的幂,1≤a≤109 ,1≤b≤109 )。
Output
每组数据输出一行,包含一个整数表示答案模109+7 的余数。
Sample Input
Copy
1
16 1 1
Sample Output
Copy
7872
这个是c++wa的代码
#include
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
#pragma GCC optimize(2)
const int maxx=1e5+15;
const ll mod=1e9+7;
using namespace std;
ll d[200];
ll jishu(ll a,ll b,ll n)
{
ll a1,a2,a3,a4,a5;
a1=(n*n)%mod;
a2=(b*n)%mod;
a3=(a1*a2)%mod;
a4=(a*(n-1))%mod;
a5=(a4*a1)%mod;
ll ans1=(a3+a5)%mod;
ll x=n/2;
a1=(x*x*18)%mod;
return ans1;
}
using namespace std;
ll oushu(ll a,ll b,ll n)
{
ll a1,a2,a3,a4,a5;
ll x=n/2;
a1=(x*x*18*a)%mod;
return a1;
}
int main()
{
ll i,j,k,t,m,n;
ll a,b,ans2;
ll cnt=0;
scanf("%lld",&t);
while(t--)
{
scanf("%lld",&n);
scanf("%lld%lld",&a,&b);
if(n==1)
{
printf("%lld\n",b);
continue;
}
ll p=0;
while(n%2==0)
{
p++;
n>>=1;
}
d[0]=b;
for(i=1;i<=p;i++)
{
d[i]=min(jishu(a,b,pow(2,i)),oushu(a,b,pow(2,i))+7*d[i-1]);
d[i]%=mod;
}
printf("%lld\n",d[p]%mod);
}
return 0;
}
这个是java ,不太会用大数,所以写的很繁琐,凑合着看吧。
import java.math.*;
import java.util.*;
import java.math.BigInteger;
import java.util.Scanner;
public class Main {
static BigInteger jishu(BigInteger a,BigInteger b,BigInteger n){ // 直接算
BigInteger ans;
ans=BigInteger.valueOf(1);
BigInteger a1,a2,a3;
a1=n.multiply(n); a2=n.multiply(a1); a2=a2.multiply(b);
ans=n.subtract(ans);
a3=a1.multiply(ans);
a3=a3.multiply(a);
a2=a2.add(a3);
return a2;
}
static BigInteger oushu(BigInteger a,BigInteger b,BigInteger n){ // n是偶数可拆
BigInteger ans,ans18;
ans=BigInteger.valueOf(2);
ans18=BigInteger.valueOf(18);
BigInteger a1,a2;
a2=n.divide(ans);
a1=a2.multiply(a2);
a1=a1.multiply(ans18);
a1=a1.multiply(a);
return a1;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner cin = new Scanner(System.in) ;
int t;
t=cin.nextInt();
while(t!=0)
{
BigInteger[] d = new BigInteger[100];
t--;
BigInteger a,b,n,x,ans1,ans2,ans7,MOD;
MOD=BigInteger.valueOf(1000000007);
ans7=BigInteger.valueOf(7);
n=cin.nextBigInteger();
a=cin.nextBigInteger();
b=cin.nextBigInteger();
if(n.equals(BigInteger.valueOf(1)))
{
System.out.println(b);
}
else
{
d[0]=b;
int i,j;
for(i=1;i<=50;i++) // 从1,2,4,8一直推到n
{
long p=1;
for(j=1;j<=i;j++)
{
p*=2;
}
x=BigInteger.valueOf(p);
ans1=jishu(a,b,x);
ans2=oushu(a,b,x);
d[i]=ans1.min(ans2.add(d[i-1].multiply(ans7))); // 保留最优值。
if(x.equals(n)) // 推到n了结束
{
break;
}
}
System.out.println(d[i].mod(MOD));
}
}
}
}
Accepts: 197
Submissions: 1721
Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 32768/32768 K (Java/Others)
Problem Description
我们知道Shannon's Switching Game是一个在图(graph)上玩的游戏,它的必胜策略和图的两个不相交的生成树有关。你不需要了解这个游戏。
本题中我们考虑Totori's Switching Game(架空)。它的定义很简单, 在一个图(可能有重边,但是没有自环)中,若存在kk个生成树,且它们的边互不相同,则玩家胜利,否则玩家失败。
Input
第一行一个整数tt表示数据组数(1\le t\le 201≤t≤20)。
接下来每组数据的第一行包含三个正整数n,m,kn,m,k,依次表示图的点数边数和题面里的kk(2\le n\le 300, 1\le m\le 300, 1\le k\le 3002≤n≤300,1≤m≤300,1≤k≤300)。
接下来mm行每行两个不同的正整数a,ba,b表示图中一条连接aa和bb的边(1\le a, b\le n1≤a,b≤n)。
Output
对每组数据输出一行。若玩家胜利,则输出"Yes",否则输出"No"。
Sample Input
2
2 2 2
1 2
2 1
3 4 2
1 2
1 2
1 2
2 3
Sample Output
Yes
No
#include
#define mem(a,b) memset(a,b,sizeof(a)) #define ll long long #pragma GCC optimize(2) const int maxx=1e5+15; const ll mod=1e9+7; using namespace std; map biaoji; ll x[maxx],y[maxx]; int main() { ll i,j,k,t,m,n; ll a,b,ans2; ll cnt=0; scanf("%lld",&t); while(t--) { biaoji.clear(); scanf("%lld",&n); scanf("%lld%lld",&m,&k); ll minl=1000000; for(i=1;i<=m;i++) { scanf("%lld%lld",&x[i],&y[i]); biaoji[x[i]]++; biaoji[y[i]]++; } for(i=1;i<=m;i++) { minl=min(minl,biaoji[x[i]]); minl=min(minl,biaoji[y[i]]); } m=(int)(m/(n-1)); minl=min(m,minl); if(minl>=k) printf("Yes\n"); else printf("No\n"); } return 0; }